using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using UnityEngine;

namespace Core
{
    class BMS
    {
        // metadata

        public string title;
        public double bpm;
        public string genre;
        public string author;

        public List<BmsNote> notes = new List<BmsNote>();

        public Level ToLevel()
        {
            var level = new Level();

            // sort all notes
            notes.Sort((note1, note2) =>
            {
                var diff = note1.barTime - note2.barTime;

                if (diff < 0)
                    return -1;
                else if (diff == 0)
                    return 0;
                else
                    return 1;
            });

            // convert all bms note to level note
            foreach (var note in notes)
            {
                var levelNote = Note.Create(note, bpm);

                if (levelNote != null)
                    level.AddNote(levelNote);
            }

            return level;
        }
    }

    class BmsNote
    {
        public string num;
        public string lane;
        public double barTime;
    }

    class BmsParser
    {
        private static char[] SEP_NEWLINE = { '\n' };
        private static char[] SEP_SPACE = { ' ' };
        private static char[] SEP_COLON = { ':' };

        private static Regex RX_DATALINE = new Regex(@"#[0-9]{5}");

        public BMS Parse(string raw)
        {
            var lines = raw.Split(SEP_NEWLINE);

            var bms = new BMS();

            foreach (var line in lines)
            {
                // metadata
                if (line.StartsWith("#TITLE"))
                    bms.title = line.Substring(line.IndexOf(' ') + 1);

                if (line.StartsWith("#GENRE"))
                    bms.genre = line.Substring(line.IndexOf(' ') + 1);

                if (line.StartsWith("#BPM"))
                    bms.bpm = double.Parse(line.Substring(line.IndexOf(' ') + 1));

                if (line.StartsWith("#ARTIST"))
                    bms.author = line.Substring(line.IndexOf(' ') + 1);

                // data lane
                if (RX_DATALINE.IsMatch(line))
                {
                    var bar = int.Parse(line.Substring(1, 3));
                    var lane = line.Substring(4, 2);
                    var data = line.Substring(7).Trim();

                    // no support for variable bar length or bpm yet
                    if ((data.Length & 1) == 1 || data.Contains("."))
                    {
                        // ignore these lines
                    }

                    var denominator = data.Length / 2;

                    // process notes in the bar
                    for (int i = 0; i < data.Length; i += 2)
                    {
                        var num = data.Substring(i, 2);
                        var barTime = bar + i / (double)denominator;

                        // ignore empty notes
                        if (num != "00")
                        {
                            var note = new BmsNote();

                            note.num = num;
                            note.lane = lane;
                            note.barTime = barTime;

                            bms.notes.Add(note);
                        }
                    }
                }
            }

            Debug.Log(bms.author);
            Debug.Log(bms.bpm);
            Debug.Log(bms.title);
            Debug.Log(bms.genre);
            return bms;
        }
    }
}