// SPDX-License-Identifier: Unlicense

#ifndef SNG_H
#define SNG_H

#include "type.h"

#ifdef SHR3D_PSARC

#include <vector>

namespace Sng
{
  enum struct NoteTuning : u32
  {
    bpm_tempo = 0x00000004
  };

  enum struct ChordMask : u32
  {
    arpeggio = 0x00000001,
    nop = 0x00000002
  } BIT_FLAGS(ChordMask);

  enum struct NoteFlags : u32
  {
    undefined = 0x00000000,
    numbered = 0x00000001
  } BIT_FLAGS(NoteFlags);

  enum struct NoteMask : u32
  {
    undefined = 0x0,
    chord = 0x02,
    open = 0x04,
    frethandMute = 0x08,
    tremolo = 0x10,
    harmonic = 0x20,
    palmMute = 0x40,
    slap = 0x80,
    pluck = 0x0100,
    pop = 0x0100,
    hammerOn = 0x0200,
    pullOff = 0x0400,
    slide = 0x0800,
    bend = 0x1000,
    sustain = 0x2000,
    tap = 0x4000,
    pinchHarmonic = 0x8000,
    vibrato = 0x010000,
    mute = 0x020000,
    ignore = 0x040000,
    leftHand = 0x00080000,
    rightHand = 0x00100000,
    highDensity = 0x200000,
    slideUnpitchedTo = 0x400000,
    single = 0x00800000,
    chordNotes = 0x01000000,
    doubleStop = 0x02000000,
    accent = 0x04000000,
    parent = 0x08000000,
    child = 0x10000000,
    arpeggio = 0x20000000,
    strum = 0x80000000,
    articulations_rh = 0x0000C1C0,
    articulations_lh = 0x00020628,
    articulations = 0x0002FFF8,
    rotation = 0x0000C1E0 // this was named rotation_disable before it works like more like it is an enable.
  } BIT_FLAGS(NoteMask);

  struct Info
  {
    struct Bpm
    {
      f32 time;
      i16 measure;
      i16 beat;
      i32 phraseIteration;
      i32 mask;
    };
    std::vector<Bpm> bpm;

    struct Level_
    {
      u8 solo;
      u8 disparity;
      u8 ignore;
      u8 paddin;
      i32 maxDifficulty;
      i32 phraseIterationLinks;
      char name[32];
    };
    std::vector<Level_> phrase;

    struct Chord
    {
      ChordMask mask;
      i8 frets[6];
      i8 fingers[6];
      i32 notes[6];
      char name[32];
    };
    std::vector<Chord> chord;

    struct BendData
    {
      f32 time;
      f32 step;
      i16 unk3_0;
      u8 unk4_0;
      u8 unk5;
    };

    struct BendData32
    {
      BendData bendData32[32];
      i32 UsedCount;
    };

    struct ChordNotes
    {
      NoteMask noteMask[6];
      BendData32 bendData[6];
      u8 slideTo[6];
      u8 slideUnpitchTo[6];
      i16 vibrato[6];
    };
    std::vector<ChordNotes> chordNotes;

    struct Vocal
    {
      f32 time;
      i32 note;
      f32 length;
      char lyric[48];
    };
    std::vector<Vocal> vocal;
    struct SymbolsHeader
    {
      i32 unk1;
      i32 unk2;
      i32 unk3;
      i32 unk4;
      i32 unk5;
      i32 unk6;
      i32 unk7;
      i32 unk8;
    };
    std::vector<SymbolsHeader> symbolsHeader;

    struct SymbolsTexture
    {
      char font[128];
      i32 fontpathLength;
      i32 unk10;
      i32 width;
      i32 height;
    };
    std::vector<SymbolsTexture> symbolsTexture;

    struct SymbolDefinition
    {
      struct Rect
      {
        f32 yMin;
        f32 xMin;
        f32 yMax;
        f32 xMax;
      };

      char text[12];
      Rect rectOutter;
      Rect rectInner;
    };
    std::vector<SymbolDefinition> symbolDefinition;

    struct PhraseIteration
    {
      i32 phraseId;
      f32 startTime;
      f32 nextPhraseTime;
      i32 difficulty[3];
    };
    std::vector<PhraseIteration> phraseIteration;

    struct PhraseExtraInfoByLevel
    {
      i32 phraseId;
      i32 difficulty;
      i32 empty;
      u8 levelJump;
      i16 redundant;
      u8 padding;
    };
    std::vector<PhraseExtraInfoByLevel> phraseExtraInfoByLevel;

    struct NLinkedDifficulty
    {
      i32 levelBreak;
      i32 phraseCount;
      std::vector<i32> nLDPhrase;
    };
    std::vector<NLinkedDifficulty> nLinkedDifficulty;

    struct Action
    {
      f32 time;
      u8 actionName[256];
    };
    std::vector<Action> action;

    struct Event
    {
      f32 time;
      u8 eventName[256];
    };
    std::vector<Event> event;

    struct Tone
    {
      f32 time;
      i32 toneId;
    };
    std::vector<Tone> tone;

    struct Dna
    {
      f32 time;
      i32 dnaId;
    };
    std::vector<Dna> dna;

    struct Section
    {
      char name[32];
      i32 number;
      f32 startTime;
      f32 endTime;
      i32 startPhraseIterationId;
      i32 endPhraseIterationId;
      u8 stringMask[36];
    };
    std::vector<Section> section;

    struct Arrangement
    {
      struct Anchor
      {
        f32 startBeatTime;
        f32 endBeatTime;
        f32 unk3_FirstNoteTime;
        f32 unk4_LastNoteTime;
        u8 fretId;
        u8 padding[3];
        i32 width;
        i32 phraseIterationId;
      };

      struct AnchorExtension
      {
        f32 beatTime;
        u8 fretId;
        i32 unk2_0;
        i16 unk3_0;
        u8 unk4_0;
      };

      struct Fingerprint
      {
        i32 chordId;
        f32 startTime;
        f32 endTime;
        f32 unk3_FirstNoteTime;
        f32 unk4_LastNoteTime;
      };

      struct Note
      {
        NoteMask noteMask;
        NoteFlags noteFlags;
        u32 hash;
        f32 time;
        i8 stringIndex;
        i8 fretId;
        i8 anchorFretId;
        i8 anchorWidth;
        i32 chordId;
        i32 chordNotesId;
        i32 phraseId;
        i32 phraseIterationId;
        i16 fingerPrintId[2];
        i16 nextIterNote;
        i16 prevIterNote;
        i16 parentPrevNote;
        i8 slideTo;
        i8 slideUnpitchTo;
        i8 leftHand; // also called finger on shred.
        i8 tap;
        i8 pickDirection;
        i8 slap;
        i8 pluck;
        i16 vibrato;
        f32 sustain;
        f32 maxBend;
        std::vector<BendData> bendData;
      };

      i32 difficulty;
      std::vector<Anchor> anchors;
      std::vector<AnchorExtension> anchorExtensions;
      std::vector<Fingerprint> fingerprints1; // for chords
      std::vector<Fingerprint> fingerprints2; // for arpeggios
      std::vector<Note> notes;
      i32 phraseCount;
      std::vector<f32> averageNotesPerIteration;
      i32 phraseIterationCount1;
      std::vector<i32> notesInIteration1;
      i32 phraseIterationCount2;
      std::vector<i32> notesInIteration2;
    };
    std::vector<Arrangement> arrangements;

    struct Metadata
    {
      f64 maxScore;
      f64 maxNotesAndChords;
      f64 maxNotesAndChordsReal;
      f64 pointsPerNote;
      f32 firstBeatLength;
      f32 startTime;
      u8 capoFretId;
      char lastConversionDateTime[32];
      i16 part;
      f32 songLength;
      i32 stringCount;
      std::vector<i16> tuning;
      f32 unk11FirstNoteTime;
      f32 unk12FirstNoteTime;
      i32 maxDifficulty;
    };
    Metadata metadata;
  };

  Sng::Info parse(const std::vector<u8>& sngData);
}

#endif // SHR3D_PSARC

#endif // SNG_H
