using TMPro;
using System.Linq;
using UnityEngine;
using UnityEngine.Events;
using System.Collections.Generic;
using System;

public class CharacterDropdown : MonoBehaviour
{
    [SerializeField] private TMP_Dropdown MainDropdown;
    [SerializeField] private TMP_InputField MainLabel;
    public List<string> DropdownLabels = new List<string>() { "Character", "Costume" };
    public List<TMP_Dropdown> Dropdowns = new List<TMP_Dropdown>();
    public List<TMP_InputField> Labels = new List<TMP_InputField>();
    private bool _awake;

    private void Awake()
    {
        if (_awake) return;
        _awake = true;
        Rebuild();
    }

    private void Rebuild()
    {
        var labelParent = MainLabel.transform.parent;
        var dropdownParent = MainDropdown.transform.parent;

        MainDropdown.ClearOptions();
        Dropdowns.Clear();
        Dropdowns.Add(MainDropdown);

        foreach (var child in dropdownParent.GetComponentsInChildren<TMP_Dropdown>())
        {
            if (child != MainDropdown) Destroy(child);
        }
        foreach (var child in labelParent.GetComponentsInChildren<TMP_Dropdown>())
        {
            if (child != MainLabel) Destroy(child);
        }

        MainDropdown.name = DropdownLabels[0];
        MainLabel.text = DropdownLabels[0];

        foreach (var label in DropdownLabels.Skip(1))
        {
            var dd = Instantiate(MainDropdown, dropdownParent);
            dd.name = "dropdown_" + label;
            var ll = Instantiate(MainLabel, labelParent);
            ll.name = label + " (TMP)";
            ll.text = label;
            Dropdowns.Add(dd);
        }
    }

    public void SetData(List<CharacterAsset> characters)
    {
        Awake();
        SetDropdownData(0, characters.Select(c => c.Category).Distinct().ToList(), true, true);

        UnityAction<int> groupCallback = (index) =>
        {
            if (index == 0) return;

            var category = GetOption(0);
            SetDropdownData(1, characters.Where(c => c.Category == category).Select(c => c.Id).Distinct().ToList(), true, true);
            //SetDropdownData(2, new List<string>(), true, true);
        };

        UnityAction<int> charaCallback = (index) =>
        {
            if (index == 0) return;

            var category = GetOption(0);
            var id = GetOption(1);
            var costumes = characters.Where(c => c.Category == category && c.Id == id);
            var costume = costumes.FirstOrDefault(c => c.Costume == "common");
            costume ??= costumes.First();
            DanMachiModelBuilder.Instance.SpawnCharacter(costume);
            //SetDropdownData(2, characters.Where(c => c.Category == category && c.Id == id).Select(c => c.Costume).ToList(), true, true);
        };

        //UnityAction<int> costumeCallback = (index) =>
        //{
        //    var chara = DanMachiAssetLibrary.Instance.GetCharacter(GetOption(0), GetOption(1), GetOption(2));
        //    StartCoroutine(DanMachiModelBuilder.Instance.SpawnAsset(AssetTypes.Character, chara));
        //};

        SetCallbacks(new List<UnityAction<int>>()
        {
            groupCallback,
            charaCallback
        });
    }

    public void SetCallbacks(List<UnityAction<int>> callbacks)
    {
        if (callbacks.Count < Dropdowns.Count)
        {
            Error.Log(Color.red, $"Incorrect number of callbacks for dropdowns. Got {callbacks.Count}, required {Dropdowns.Count}");
        }

        for (int i = 0; i < Dropdowns.Count; i++)
        {
            Dropdowns[i].onValueChanged.RemoveAllListeners();
            Dropdowns[i].onValueChanged.AddListener(callbacks[i]);
        }
    }

    public void OnDropdownSelected(int selection)
    {
        if (selection == 0)
        {
            Debug.LogError("Delete Current");
        }
        StartCoroutine(ModelBuilder.GetInstance().SpawnAsset(AssetTypes.Character, MainDropdown.options[selection].text));
    }

    public void SetDropdownData(string label, List<string> options, bool nullValue = false, bool sortValues = false)
    {
        var depth = DropdownLabels.IndexOf(label);
        SetDropdownData(depth, options, nullValue, sortValues);
    }

    public string GetOption(int depth)
    {
        if (Dropdowns[depth].value == 0) return null;
        return Dropdowns[depth].options[Dropdowns[depth].value].text;
    }

    public void SetDropdownData(int depth, List<string> options, bool nullValue = false, bool sortValues = false)
    {
        if (depth >= Dropdowns.Count || depth < 0)
        {
            Error.Log(Color.red, $"Dropdown {depth} out of range");
            return;
        }
        ModelViewerInterface.SetDropdownData(Dropdowns[depth], options, nullValue, sortValues);
    }
}
