using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
#if UNITY_6000_0_OR_NEWER
using UnityEngine.InputSystem;
#endif

public class UIManager : MonoBehaviour
{
    [Header("References")]
    [SerializeField] private CameraController _cameraController;

    [Header("UI - Title")]
    [SerializeField] private Text _titleText;

    [Header("UI - NPC List (Left)")]
    [SerializeField] private Transform _npcListContent;
    [SerializeField] private GameObject _npcButtonPrefab;

    [Header("UI - Camera Control")]
    [SerializeField] private Toggle _cameraToggle;
    [SerializeField] private Button _settingsBtn;
    [SerializeField] private GameObject _timerPanel;
    [SerializeField] private Button _decBtn;
    [SerializeField] private Button _incBtn;
    [SerializeField] private Text _switchTimeText;
    [SerializeField] private Text _currentNPCText;

    [Header("UI - Language")]
    [SerializeField] private Button _langBtn;
    [SerializeField] private Text _langText;
    [SerializeField] private GameObject _langPanel;

    [Header("UI - Map")]
    [SerializeField] private Button _mapDecBtn;
    [SerializeField] private Button _mapIncBtn;
    [SerializeField] private Text _mapNameText;

    private List<NPC> _spawnedNPCs = new();
    private List<Toggle> _npcToggles = new();
    private HashSet<int> _selectedSet = new();

    System.Collections.IEnumerator Start()
    {
        yield return null;

        _spawnedNPCs.AddRange(FindObjectsByType<NPC>(FindObjectsSortMode.None));
        _spawnedNPCs.Sort((a, b) => string.Compare(a.Data.NPCName, b.Data.NPCName));

        BuildNPCList();
        SetupControls();
    }

    void BuildNPCList()
    {
        for (int i = 0; i < _spawnedNPCs.Count; i++)
        {
            var npc = _spawnedNPCs[i];
            var btnObj = Instantiate(_npcButtonPrefab, _npcListContent);

            var nameText = btnObj.transform.Find("NameText");
            if (nameText != null)
                nameText.GetComponent<Text>().text = npc.Data.NPCName;

            var toggle = btnObj.GetComponentInChildren<Toggle>();
            if (toggle != null)
            {
                int idx = i;
                toggle.isOn = false;
                toggle.onValueChanged.AddListener(isOn => OnNPCToggleChanged(idx, isOn));
                _npcToggles.Add(toggle);
            }

            var btn = btnObj.GetComponent<Button>();
            if (btn != null)
            {
                var capturedNPC = npc;
                btn.onClick.AddListener(() => MoveCameraTo(capturedNPC));
            }
        }
    }

    void SetupControls()
    {
        if (_settingsBtn != null)
            _settingsBtn.onClick.AddListener(ToggleTimerPanel);

        if (_timerPanel != null)
            _timerPanel.SetActive(false);

        if (_cameraToggle != null)
        {
            _cameraToggle.isOn = false;
            _cameraToggle.onValueChanged.AddListener(OnCameraToggleChanged);
        }

        if (_decBtn != null)
            _decBtn.onClick.AddListener(() => AdjustSwitchTime(-0.5f));
        if (_incBtn != null)
            _incBtn.onClick.AddListener(() => AdjustSwitchTime(0.5f));

        if (_langBtn != null)
            _langBtn.onClick.AddListener(ToggleLangPanel);

        if (_langPanel != null)
        {
            BuildLangPanel();
            _langPanel.SetActive(false);
        }

        if (_mapDecBtn != null)
            _mapDecBtn.onClick.AddListener(() => ChangeMap(-1));
        if (_mapIncBtn != null)
            _mapIncBtn.onClick.AddListener(() => ChangeMap(1));

        UpdateSwitchTimeText();
        UpdateCurrentNPCText("Free");
        UpdateLangText();
        UpdateMapText();
    }

    void Update()
    {
        if (_cameraController == null) return;

        // C key: cycle language
        #if UNITY_6000_0_OR_NEWER
        if (Keyboard.current != null && Keyboard.current.cKey.wasPressedThisFrame)
        #else
        if (Input.GetKeyDown(KeyCode.C))
        #endif
        {
            if (WorldManager.Instance != null)
            {
                WorldManager.Instance.CycleLanguage();
                UpdateLangText();
            }
        }

        var target = _cameraController.GetCurrentTarget();
        if (target != null && _cameraController.CameraMode != CameraController.Mode.FreeDrag)
        {
            var npc = target.GetComponent<NPC>();
            UpdateCurrentNPCText(npc != null ? npc.Data.NPCName : target.name);
        }
    }

    void MoveCameraTo(NPC npc)
    {
        if (_cameraController == null || npc == null) return;

        var pos = npc.transform.position;
        pos.z = _cameraController.transform.position.z;
        _cameraController.transform.position = pos;
        UpdateCurrentNPCText(npc.Data.NPCName);
    }

    void OnNPCToggleChanged(int index, bool isOn)
    {
        if (isOn)
            _selectedSet.Add(index);
        else
            _selectedSet.Remove(index);

        ApplyTracking();
    }

    void OnCameraToggleChanged(bool isOn)
    {
        // Track All: toggle all NPC toggles
        _selectedSet.Clear();
        for (int i = 0; i < _npcToggles.Count; i++)
        {
            _npcToggles[i].SetIsOnWithoutNotify(isOn);
            if (isOn) _selectedSet.Add(i);
        }
        ApplyTracking();
    }

    void ApplyTracking()
    {
        if (_cameraController == null) return;

        if (_selectedSet.Count == 0)
        {
            _cameraController.CameraMode = CameraController.Mode.FreeDrag;
            _cameraController.FollowTarget = null;
            UpdateCurrentNPCText("Free");
            return;
        }

        if (_selectedSet.Count == 1)
        {
            foreach (var idx in _selectedSet)
            {
                _cameraController.FollowTarget = _spawnedNPCs[idx].transform;
                _cameraController.CameraMode = CameraController.Mode.FollowNPC;
            }
            return;
        }

        var targets = new List<Transform>();
        foreach (var idx in _selectedSet)
        {
            if (idx < _spawnedNPCs.Count)
                targets.Add(_spawnedNPCs[idx].transform);
        }

        if (targets.Count > 0)
        {
            _cameraController.SetRoundRobinTargets(targets.ToArray());
            _cameraController.CameraMode = CameraController.Mode.RoundRobin;
        }
    }

    void ToggleTimerPanel()
    {
        if (_timerPanel != null)
            _timerPanel.SetActive(!_timerPanel.activeSelf);
    }

    void AdjustSwitchTime(float delta)
    {
        if (_cameraController == null) return;
        float newVal = Mathf.Clamp(_cameraController.SwitchInterval + delta, 1f, 30f);
        _cameraController.SwitchInterval = newVal;
        UpdateSwitchTimeText();
    }

    void UpdateSwitchTimeText()
    {
        if (_switchTimeText != null && _cameraController != null)
            _switchTimeText.text = $"{_cameraController.SwitchInterval:F1}s";
    }

    void UpdateCurrentNPCText(string text)
    {
        if (_currentNPCText != null)
            _currentNPCText.text = text;
    }

    void ToggleLangPanel()
    {
        if (_langPanel != null)
            _langPanel.SetActive(!_langPanel.activeSelf);
    }

    void BuildLangPanel()
    {
        var languages = System.Enum.GetValues(typeof(NPCData.Language));
        foreach (NPCData.Language lang in languages)
        {
            var btnObj = new GameObject(lang.ToString());
            btnObj.transform.SetParent(_langPanel.transform, false);

            var rt = btnObj.AddComponent<RectTransform>();
            rt.sizeDelta = new Vector2(0, 30);

            var img = btnObj.AddComponent<Image>();
            img.color = new Color(0.2f, 0.2f, 0.25f, 0.95f);

            var btn = btnObj.AddComponent<Button>();
            btn.targetGraphic = img;

            var textObj = new GameObject("Text");
            textObj.transform.SetParent(btnObj.transform, false);
            var tRT = textObj.AddComponent<RectTransform>();
            tRT.anchorMin = Vector2.zero;
            tRT.anchorMax = Vector2.one;
            tRT.offsetMin = Vector2.zero;
            tRT.offsetMax = Vector2.zero;
            var text = textObj.AddComponent<Text>();
            var label = lang.ToString();
            text.text = label.Contains("_") ? label.Replace("_", " ") : label;
            text.fontSize = 20;
            text.alignment = TextAnchor.MiddleCenter;
            text.color = Color.white;
            text.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");

            var le = btnObj.AddComponent<LayoutElement>();
            le.preferredHeight = 44;
            le.flexibleWidth = 1;

            var capturedLang = lang;
            btn.onClick.AddListener(() => SelectLanguage(capturedLang));
        }
    }

    void SelectLanguage(NPCData.Language lang)
    {
        if (WorldManager.Instance == null) return;
        WorldManager.Instance.SetLanguage(lang);
        UpdateLangText();
        if (_langPanel != null)
            _langPanel.SetActive(false);
    }

    void UpdateLangText()
    {
        if (_langText == null || WorldManager.Instance == null) return;
        var lang = WorldManager.Instance.CurrentLanguage.ToString();
        _langText.text = lang.Contains("_") ? lang.Replace("_", "\n") : lang;
    }

    void ChangeMap(int dir)
    {
        if (WorldManager.Instance == null) return;
        var pf = FindAnyObjectByType<Pathfinder>();
        if (pf == null || pf.TilemapSets == null) return;

        int count = pf.TilemapSets.Length;
        int newIdx = (pf.ActiveSetIndex + dir + count) % count;
        WorldManager.Instance.SetActiveMap(newIdx);

        // Rebuild NPC list
        StartCoroutine(RebuildNPCList());
        UpdateMapText();
    }

    System.Collections.IEnumerator RebuildNPCList()
    {
        yield return null;

        _spawnedNPCs.Clear();
        _npcToggles.Clear();
        _selectedSet.Clear();

        // Clear old list
        foreach (Transform child in _npcListContent)
            Destroy(child.gameObject);

        _spawnedNPCs.AddRange(FindObjectsByType<NPC>(FindObjectsSortMode.None));
        _spawnedNPCs.Sort((a, b) => string.Compare(a.Data.NPCName, b.Data.NPCName));
        BuildNPCList();
        UpdateCurrentNPCText("Free");
    }

    void UpdateMapText()
    {
        if (_mapNameText == null) return;
        var pf = FindAnyObjectByType<Pathfinder>();
        if (pf == null || pf.TilemapSets == null) return;
        _mapNameText.text = pf.TilemapSets[pf.ActiveSetIndex].Name;
    }
}
