using System.Collections.Generic;
using UnityEngine;

public class NPCTalkSystem : MonoBehaviour
{
    private const float SenseRadius = 1.5f;
    private const float TalkDistance = 0.6f;

    private SpeechBubbleManager _bubbleManager;
    private NPCData _data;
    private SpeechBubble _currentBubble;

    private float _talkCooldown;
    private NPC _lastTalkPartner;

    // Turn-based talk
    private NPC _talkTarget;
    private float _turnTimer;
    private int _turnCount;
    private int _totalTurns;
    private bool _isFirstSpeaker;

    private static List<NPC> s_allNPCs = new();

    public NPC TalkTarget => _talkTarget;
    public bool IsOnCooldown => _talkCooldown > 0;

    public void Initialize(NPCData data, SpeechBubbleManager bubbleManager)
    {
        _data = data;
        _bubbleManager = bubbleManager;
        s_allNPCs.Add(GetComponent<NPC>());
    }

    void OnDestroy()
    {
        s_allNPCs.Remove(GetComponent<NPC>());
    }

    public void Tick()
    {
        if (_talkCooldown > 0) _talkCooldown -= Time.deltaTime;
    }

    // Check if there is a talkable NPC nearby
    public NPC CheckNearby(NPC self)
    {
        if (_talkCooldown > 0) return null;

        foreach (var other in s_allNPCs)
        {
            if (other == self) continue;
            if (other == _lastTalkPartner) continue;
            if (other.CurrentState == NPC.State.Talk || other.CurrentState == NPC.State.Approach) continue;
            if (other.CurrentState != NPC.State.Idle && other.CurrentState != NPC.State.Move) continue;

            var otherTalk = other.GetComponent<NPCTalkSystem>();
            if (otherTalk.IsOnCooldown) continue;

            float dist = Vector2.Distance(transform.position, other.transform.position);
            if (dist < SenseRadius)
                return other;
        }
        return null;
    }

    // Check if within talk distance
    public bool IsInTalkRange(NPC other)
    {
        return Vector2.Distance(transform.position, other.transform.position) < TalkDistance;
    }

    // Begin approach
    public void SetTarget(NPC other)
    {
        _talkTarget = other;
    }

    public void ClearTarget()
    {
        _talkTarget = null;
    }

    // Start talk
    public void StartTalk(NPC other, bool isFirstSpeaker)
    {
        _talkTarget = other;
        _isFirstSpeaker = isFirstSpeaker;
        _turnCount = 0;
        _totalTurns = Random.Range(4, 7);
        _turnTimer = 0.5f;
    }

    // Update talk each frame — returns true when talk ends
    public bool UpdateTalk()
    {
        _turnTimer -= Time.deltaTime;
        if (_turnTimer > 0) return false;

        if (_turnCount >= _totalTurns)
        {
            EndTalk();
            return true;
        }

        bool isMyTurn = (_turnCount % 2 == 0) == _isFirstSpeaker;
        if (isMyTurn)
            ShowBubble(NPC.State.Talk);
        else
            HideBubble();

        _turnCount++;
        _turnTimer = Random.Range(1.5f, 2.5f);
        return false;
    }

    public void EndTalk()
    {
        HideBubble();
        _lastTalkPartner = _talkTarget;

        var partner = _talkTarget;
        _talkTarget = null;
        _talkCooldown = Random.Range(3f, 5f);

        if (partner != null && partner.CurrentState == NPC.State.Talk)
        {
            var partnerTalk = partner.GetComponent<NPCTalkSystem>();
            partnerTalk.EndTalk();
            partner.SetState(NPC.State.Idle);
        }
    }

    // Show speech bubble on state change
    public void ShowBubble(NPC.State state)
    {
        var lang = WorldManager.Instance != null ? WorldManager.Instance.CurrentLanguage : NPCData.Language.EN;
        var dialogue = _data.GetRandomDialogue(state, lang);
        if (dialogue == null || _bubbleManager == null) return;

        if (_currentBubble != null && _currentBubble.IsActive)
            _bubbleManager.Return(_currentBubble);
        _currentBubble = _bubbleManager.Get(transform, dialogue);
    }

    public void HideBubble()
    {
        if (_currentBubble != null && _currentBubble.IsActive)
            _bubbleManager.Return(_currentBubble);
        _currentBubble = null;
    }

    public bool CanApproach(NPC other)
    {
        if (_talkCooldown > 0) return false;
        if (other.CurrentState == NPC.State.Talk) return false;
        return true;
    }
}
