using Melanchall.DryWetMidi.Common;
using Melanchall.DryWetMidi.Core;

namespace ADToGMConverter.Services;

public class TrackResolver
{
    private readonly List<TrackChunk> trackChunks;
    public TrackResolver(IEnumerable<TrackChunk> chunks)
    {
        trackChunks = chunks.ToList();
    }
    
    public Dictionary<TrackChunk, string> MapTrackChunksNames()
    {
        return MapTrackChunksNames(trackChunks);
    }

    public static Dictionary<TrackChunk, string> MapTrackChunksNames(List<TrackChunk> chunks)
    {
        var dictionary = new Dictionary<TrackChunk, string>();

        foreach (var chunk in chunks)
        {
            bool isNamed = false;
            foreach (var _event in chunk.Events)
            {
                if (_event is SequenceTrackNameEvent nameEvent)
                {
                    dictionary.Add(chunk, nameEvent.Text);
                    isNamed = true;
                    break;
                }
            }
            if (!isNamed)
            {
                dictionary.Add(chunk, "NoName");
            }
        }

        return dictionary;
    }

    // Полный маппинг AD2 -> General MIDI
    private static readonly Dictionary<int, int> Ad2ToGmMapping = new Dictionary<int, int>
    {
        // Бас-бочка
        { 36, 36 }, // Kick -> Bass Drum 1
        
        // Рабочий барабан - основное
        { 38, 38 }, // Snare Open Hit -> Acoustic Snare
        { 40, 38 }, // Snare Open Hit (db) -> Acoustic Snare
        
        // Рабочий барабан - римшоты и специальные звуки
        { 37, 37 }, // Snare Rimshot -> Side Stick
        { 39, 37 }, // Snare Rimshot (db) -> Side Stick
        { 42, 37 }, // Snare SideStick -> Side Stick
        { 44, 37 }, // Snare RimClick -> Side Stick
        
        // Рабочий барабан - щетки и дополнительные звуки
        { 41, 38 }, // Snare Shallow Rimshot -> Acoustic Snare
        { 43, 38 }, // Snare Shallow Hit -> Acoustic Snare
        
        // Хай-хэт
        { 48, 44 }, // HiHat Pedal Closed -> Pedal Hi-Hat
        { 49, 42 }, // HiHat Closed 1 Tip -> Closed Hi-Hat
        { 50, 42 }, // HiHat Closed 1 Shaft -> Closed Hi-Hat
        { 51, 42 }, // HiHat Closed 2 Tip -> Closed Hi-Hat
        { 52, 42 }, // HiHat Closed 2 Shaft -> Closed Hi-Hat
        { 53, 42 }, // HiHat Closed Bell -> Closed Hi-Hat
        { 54, 46 }, // HiHat Open A -> Open Hi-Hat
        { 55, 46 }, // HiHat Open B -> Open Hi-Hat
        { 56, 46 }, // HiHat Open C -> Open Hi-Hat
        { 57, 46 }, // HiHat Open D -> Open Hi-Hat
        { 58, 46 }, // HiHat Open Bell -> Open Hi-Hat
        { 59, 46 }, // HiHat Pedal Open -> Open Hi-Hat
        
        // Томы
        { 65, 41 }, // Tom 4 Open Hit -> Low Floor Tom
        { 66, 41 }, // Tom 4 Rimshot -> Low Floor Tom
        { 67, 45 }, // Tom 3 Open Hit -> Low Tom
        { 68, 45 }, // Tom 3 Rimshot -> Low Tom
        { 69, 47 }, // Tom 2 Open Hit -> Low-Mid Tom
        { 70, 47 }, // Tom 2 Rimshot -> Low-Mid Tom
        { 71, 48 }, // Tom 1 Open Hit -> Hi-Mid Tom
        { 72, 48 }, // Tom 1 Rimshot -> Hi-Mid Tom
        
        // Основные тарелки
        { 77, 49 }, // Cymbal 1 Hit -> Crash Cymbal 1
        { 79, 49 }, // Cymbal 2 Hit -> Crash Cymbal 1
        { 81, 49 }, // Cymbal 3 Hit -> Crash Cymbal 1
        { 89, 57 }, // Cymbal 4 Hit -> Crash Cymbal 2
        { 91, 57 }, // Cymbal 5 Hit -> Crash Cymbal 2
        { 93, 57 }, // Cymbal 6 Hit -> Crash Cymbal 2
        
        // Чок тарелок (преобразуем в обычные удары)
        { 78, 49 }, // Cymbal 1 Choke -> Crash Cymbal 1
        { 80, 49 }, // Cymbal 2 Choke -> Crash Cymbal 1
        { 82, 49 }, // Cymbal 3 Choke -> Crash Cymbal 1
        { 90, 57 }, // Cymbal 4 Choke -> Crash Cymbal 2
        { 92, 57 }, // Cymbal 5 Choke -> Crash Cymbal 2
        { 94, 57 }, // Cymbal 6 Choke -> Crash Cymbal 2
        
        // Райд-тарелки
        { 60, 51 }, // Ride 1 Tip -> Ride Cymbal 1
        { 61, 53 }, // Ride 1 Bell -> Ride Bell
        { 62, 51 }, // Ride 1 Shaft -> Ride Cymbal 1
        { 63, 51 }, // Ride 1 Choke -> Ride Cymbal 1
        
        { 84, 51 }, // Ride 2 Tip -> Ride Cymbal 1
        { 85, 53 }, // Ride 2 Bell -> Ride Bell
        { 86, 51 }, // Ride 2 Shaft -> Ride Cymbal 1
        { 87, 51 }, // Ride 2 Choke -> Ride Cymbal 1
        
        // Flexi зоны (преобразуем в томы)
        { 47, 38 }, // Flexi 1 Hit A -> Acoustic Snare
        { 73, 45 }, // Flexi 1 Hit B -> Low Tom
        { 74, 47 }, // Flexi 1 Hit C -> Low-Mid Tom
        { 76, 48 }, // Flexi 1 Hit D -> Hi-Mid Tom
        
        { 96, 41 }, // Flexi 2 Hit A -> Low Floor Tom
        { 97, 45 }, // Flexi 2 Hit B -> Low Tom
        { 98, 47 }, // Flexi 2 Hit C -> Low-Mid Tom
        { 99, 48 }, // Flexi 2 Hit D -> Hi-Mid Tom
        
        { 100, 41 }, // Flexi 3 Hit A -> Low Floor Tom
        { 101, 45 }, // Flexi 3 Hit B -> Low Tom
        { 102, 47 }, // Flexi 3 Hit C -> Low-Mid Tom
        { 103, 48 }, // Flexi 3 Hit D -> Hi-Mid Tom
        
        // Дополнительные звуки
        { 45, 49 }, // Ride 1 Tip (db) -> Crash Cymbal 1
        { 46, 49 }, // Cymbal 1 Hit (db) -> Crash Cymbal 1
    };

        public static void ConvertAd2ToGmDrums(TrackChunk trackChunk)
    {
        if (trackChunk == null) return;

        // Получаем все нотные события
        var noteEvents = trackChunk.Events
            .Where(e => e is NoteOnEvent || e is NoteOffEvent)
            .ToList();

        foreach (var midiEvent in noteEvents)
        {
            int originalNote;
            
            if (midiEvent is NoteOnEvent noteOnEvent)
            {
                originalNote = noteOnEvent.NoteNumber;
                if (Ad2ToGmMapping.TryGetValue(originalNote, out int newNote))
                {
                    noteOnEvent.NoteNumber = (SevenBitNumber)newNote;
                }
            }
            else if (midiEvent is NoteOffEvent noteOffEvent)
            {
                originalNote = noteOffEvent.NoteNumber;
                if (Ad2ToGmMapping.TryGetValue(originalNote, out int newNote))
                {
                    noteOffEvent.NoteNumber = (SevenBitNumber)newNote;
                }
            }
        }

        // Устанавливаем канал 9 для ударных (General MIDI standard)
        SetDrumChannel(trackChunk);
    }

    /// <summary>
    /// Устанавливает канал 9 (ударные) для всех событий трека
    /// </summary>
    private static void SetDrumChannel(TrackChunk trackChunk)
    {
        foreach (var midiEvent in trackChunk.Events)
        {
            if (midiEvent is ChannelEvent channelEvent)
            {
                channelEvent.Channel = (FourBitNumber)9; // Channel 10 in 1-based indexing
            }
        }
    }

        private static string GetNoteName(int noteNumber)
    {
        string[] noteNames = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
        int octave = noteNumber / 12 - 1;
        int noteIndex = noteNumber % 12;
        return $"{noteNames[noteIndex]}{octave}";
    }
}