import { getAsciiNoteName } from '../translators/utils';
import { Articulation, Note, NoteExample, Timing } from '../types';

export const describeExample = (example: NoteExample) => {
  return `${example.patternDescription} ${example.pitchDescription}, ${example.timingQualifier} ${
    timings[example.timing].description
  }, ${example.holdDescription}`;
};

// All examples should be in quarter notes with default velocity unless the example is specifically about velocity or timing.
// All examples should be root C4.
export const cMinorTriad: NoteExample = {
  patternDescription: 'a minor triad starting on',
  pitchDescription: 'C4',
  timingQualifier: 'on',
  timing: Timing.Quarter,
  holdDescription: 'played legato',
  notes: [
    { pitch: 48, start: 0, end: 1, velocity: 0.7874015748031497, lifted: true },
    { pitch: 51, start: 1, end: 2, velocity: 0.7874015748031497, lifted: true },
    { pitch: 60, start: 3, end: 4, velocity: 0.7874015748031497, lifted: true },
    { pitch: 55, start: 2, end: 3, velocity: 0.7874015748031497, lifted: true },
  ],
};

export const cMajorScale: NoteExample = {
  patternDescription: 'a major scale starting on',
  pitchDescription: 'C4',
  timingQualifier: 'on',
  timing: Timing.Quarter,
  holdDescription: 'played legato',
  notes: [
    { pitch: 59, start: 6, end: 7, velocity: 0.7874015748031497, lifted: true },
    { pitch: 57, start: 5, end: 6, velocity: 0.7874015748031497, lifted: true },
    { pitch: 55, start: 4, end: 5, velocity: 0.7874015748031497, lifted: true },
    { pitch: 53, start: 3, end: 4, velocity: 0.7874015748031497, lifted: true },
    { pitch: 52, start: 2, end: 3, velocity: 0.7874015748031497, lifted: true },
    { pitch: 50, start: 1, end: 2, velocity: 0.7874015748031497, lifted: true },
    { pitch: 48, start: 0, end: 1, velocity: 0.7874015748031497, lifted: true },
    { pitch: 60, start: 7, end: 8, velocity: 0.7874015748031497, lifted: true },
  ],
};

const timings = {
  [Timing.Quarter]: {
    description: 'quarter notes',
    multiplier: 1,
  },
  [Timing.Eighth]: {
    description: 'eighth notes',
    multiplier: 0.5,
  },
  [Timing.Sixteenth]: {
    description: 'sixteenth notes',
    multiplier: 0.25,
  },
  [Timing.DottedEighth]: {
    description: 'dotted eighth notes',
    multiplier: 0.75,
  },
  [Timing.Triplet]: {
    description: 'triplets',
    multiplier: 0.3333333333333333,
  },
};

export const timing =
  (timing: Timing) =>
  (example: NoteExample): NoteExample => {
    const multiplier = timings[timing].multiplier;
    const notes = example.notes
      .filter((n) => n.type !== 'Comment')
      .map((note: Note) => ({
        ...note,
        start: note.start * multiplier,
        end: note.end * multiplier,
      }));
    return {
      ...example,
      notes,
      timing,
    };
  };

export const length =
  (length: number | Articulation) =>
  (example: NoteExample): NoteExample => {
    if (length === Articulation.Legato) {
      return example;
    } else if (length === Articulation.Staccato) {
      return {
        ...example,
        holdDescription: 'played staccato',
        notes: example.notes
          .filter((n) => n.type !== 'Comment')
          .map((note: Note) => ({
            ...note,
            end: note.start + 0.25,
          })),
      };
    } else {
      return {
        ...example,
        holdDescription: `with each note held for ${length} beats`,
        notes: example.notes
          .filter((n) => n.type !== 'Comment')
          .map((note: Note) => ({
            ...note,
            end: note.start + length,
          })),
      };
    }
  };

export const root =
  (pitch: number) =>
  (example: NoteExample): NoteExample => {
    return {
      ...example,
      pitchDescription: `${getAsciiNoteName(pitch)}`,
      notes: example.notes
        .filter((n) => n.type !== 'Comment')
        .map((note: Note) => ({
          ...note,
          pitch: note.pitch - 48 + pitch,
        })),
    };
  };
