using System;
using UnityEngine;

// 보스 공격 하나의 설정. 별도 .asset 없이 BossAI 인스펙터에서 배열로 편집.
[Serializable]
public class BossAttack
{
    public string Name = "Attack";        // 디버그/식별용 이름
    public int MinPhase;                  // 이 페이즈(0부터) 이상에서만 사용 가능
    public float Range = 1.5f;            // 타겟이 이 X거리 안일 때만 사용
    public float Windup = 0.4f;           // 공격 시작 ~ 데미지 발생 (선딜)
    public float Duration = 0.9f;         // 공격 동작 전체 길이 (이 동안 이동 정지)
    public float Cooldown = 10f;           // 이 공격 자체의 재사용 대기
    public int Damage = 15;
    public Vector2 HitVelocity = new Vector2(5f, 2f);  // 피격자 넉백 (X는 보스 facing 방향으로 부호 적용)
    public string AnimationState = "BossAttack";
}

// ============================================================================
// BossAI
// ----------------------------------------------------------------------------
// 보스의 두뇌. 감지 → 추격 → 공격 상태머신.
//   - 단순 공격: BossAttack 데이터 배열 (사거리·쿨다운·페이즈 조건)
//   - 특별 스킬: BossSkill 프리팹 배열. 시전 시 Instantiate → 끝나면 스스로 파괴
//   - 행동 결정: 특별 스킬 → 단순 공격 → 추격 순으로 시도
// 같은 GameObject의 Enemy(몸)·Boss(페이즈)와 함께 동작.
// ============================================================================
[RequireComponent(typeof(Enemy))]
[RequireComponent(typeof(Rigidbody2D))]
public class BossAI : MonoBehaviour
{
    private enum AIState { Idle, Chase, Attack }

    [Header("Target")]
    [SerializeField] private Transform _target;              // 비우면 자동으로 플레이어 검색
    [SerializeField] private bool _autoFindPlayer = true;
    [SerializeField] private float _detectRange = 12f;       // 이 X거리 안에 들어오면 인지
    [SerializeField] private float _detectVerticalRange = 4f;

    [Header("Movement")]
    [SerializeField] private float _moveSpeed = 2.5f;
    [SerializeField] private float _stopDistance = 1f;       // 타겟과 이 거리 안이면 이동 정지

    [Header("Attacks")]
    [SerializeField] private BossAttack[] _attacks;
    [SerializeField] private BossSkill[] _skillPrefabs;               // 특별 스킬 프리팹 (시전 시 Instantiate)
    [SerializeField] private float _attackVerticalTolerance = 1.5f;   // 공격 적중 인정 세로 오차
    [SerializeField] private float _globalAttackCooldown = 0.6f;      // 공격/스킬 종료 후 다음 행동까지 최소 간격

    [Header("Animation")]
    [SerializeField] private string _idleAnimationState = "Idle";
    [SerializeField] private string _runAnimationState = "Run";

    private Enemy _enemy;
    private Boss _boss;
    private Health _health;
    private Rigidbody2D _rb;
    private Animator _anim;
    private SpriteRenderer _spriteRenderer;
    private IDamageable _targetDamageable;

    private AIState _state = AIState.Idle;
    private bool _hasAggro;

    private float[] _attackCooldownTimers;   // _attacks와 1:1 — 각 공격의 남은 쿨다운
    private int[] _attackPickBuffer;         // PickAttackIndex 후보 수집용 (GC 회피)
    private float[] _skillCooldownTimers;    // _skillPrefabs와 1:1 — 보스별 스킬 쿨다운
    private int[] _skillPickBuffer;          // PickSkillIndex 후보 수집용 (GC 회피)
    private float _globalCooldownTimer;      // 공격/스킬 사이 전역 대기

    private BossSkill _runningSkillInstance; // 진행 중인 스킬 인스턴스 (없거나 끝나면 null)
    private bool _skillInProgress;           // 스킬 시전 중 (인스턴스 생성 ~ 파괴)

    private BossAttack _currentAttack;       // 진행 중인 단순 공격
    private bool _isAttacking;
    private bool _attackDamageApplied;       // 이번 공격에서 데미지를 이미 줬는지
    private float _attackTimer;

    private float _facingDirection = 1f;
    private string _activeAnimationState;

    private void Awake()
    {
        _enemy = GetComponent<Enemy>();
        _boss = GetComponent<Boss>();
        _health = GetComponent<Health>();
        _rb = GetComponent<Rigidbody2D>();
        _anim = GetComponentInChildren<Animator>();
        _spriteRenderer = GetComponentInChildren<SpriteRenderer>();

        int attackCount = _attacks != null ? _attacks.Length : 0;
        _attackCooldownTimers = new float[attackCount];
        _attackPickBuffer = new int[attackCount];

        int skillCount = _skillPrefabs != null ? _skillPrefabs.Length : 0;
        _skillCooldownTimers = new float[skillCount];
        _skillPickBuffer = new int[skillCount];
    }

    private void Update()
    {
        TickCooldowns();
        ResolveTarget();

        // 페이즈 전환 중: 행동만 멈추고 애니메이션은 건드리지 않는다.
        // (Boss가 BossPhaseChange를 재생 중 — 여기서 SetState(Idle)하면 그 애니가 덮인다.)
        if (_boss != null && _boss.IsTransitioning)
        {
            if (_isAttacking) CancelAttack();
            CancelRunningSkill();
            StopMoving();
            _state = AIState.Idle;
            _activeAnimationState = null;  // 전환 종료 후 SetState가 다시 정상 재생되도록 무효화
            return;
        }

        // 사망 / 행동 불가(피격 경직·잡힘) / 타겟 없음 → 정지 + 진행 중 행동 취소.
        if (_health.IsDead || !_enemy.CanUseAI || _target == null)
        {
            if (_isAttacking) CancelAttack();
            CancelRunningSkill();
            StopMoving();
            SetState(AIState.Idle);
            return;
        }

        // 특별 스킬 진행 중이면 스킬에 전부 맡기고 대기. 인스턴스가 사라지면(종료) 후딜 부여.
        if (_skillInProgress)
        {
            if (_runningSkillInstance != null)
            {
                StopMoving();
                return;
            }
            _skillInProgress = false;
            _globalCooldownTimer = _globalAttackCooldown;
        }

        RefreshAggro();

        // 공격 중이면 facing을 고정한 채 공격 진행만 처리.
        if (_isAttacking)
        {
            TickAttack();
            return;
        }

        UpdateFacing();

        if (!_hasAggro)
        {
            StopMoving();
            SetState(AIState.Idle);
            return;
        }

        // 전역 쿨다운이 끝났으면 특별 스킬 → 단순 공격 순으로 시도. 둘 다 안 되면 추격.
        if (_globalCooldownTimer <= 0f)
        {
            int skillIndex = PickSkillIndex();
            if (skillIndex >= 0)
            {
                BeginSkill(skillIndex);
                return;
            }

            int attackIndex = PickAttackIndex();
            if (attackIndex >= 0)
            {
                BeginAttack(attackIndex);
                return;
            }
        }

        SetState(AIState.Chase);
    }

    private void FixedUpdate()
    {
        if (_rb == null) return;

        // 추격 상태에서만 X축 이동. 그 외 상태에선 손대지 않음
        // (정지는 Update에서 상태 전환 시 StopMoving으로 처리).
        if (_state != AIState.Chase || _target == null) return;

        float dx = _target.position.x - transform.position.x;
        Vector2 v = _rb.linearVelocity;
        v.x = Mathf.Abs(dx) <= _stopDistance ? 0f : Mathf.Sign(dx) * _moveSpeed;
        _rb.linearVelocity = v;
    }

    // ─── 단순 공격 ────────────────────────────────────────────────────────

    // 현재 사용 가능한 공격 후보 중 무작위 1개의 인덱스 반환. 없으면 -1.
    // 조건: 페이즈 해금 + 쿨다운 종료 + 사거리 안.
    private int PickAttackIndex()
    {
        if (_attacks == null || _attacks.Length == 0 || _target == null) return -1;

        Vector2 delta = _target.position - transform.position;
        if (Mathf.Abs(delta.y) > _attackVerticalTolerance) return -1;
        float distanceX = Mathf.Abs(delta.x);
        int phase = _boss != null ? _boss.CurrentPhase : 0;

        int candidateCount = 0;
        for (int i = 0; i < _attacks.Length; i++)
        {
            BossAttack a = _attacks[i];
            if (a == null) continue;
            if (phase < a.MinPhase) continue;             // 페이즈 미해금
            if (_attackCooldownTimers[i] > 0f) continue;  // 쿨다운 중
            if (distanceX > a.Range) continue;            // 사거리 밖
            _attackPickBuffer[candidateCount++] = i;
        }

        if (candidateCount == 0) return -1;
        return _attackPickBuffer[UnityEngine.Random.Range(0, candidateCount)];
    }

    private void BeginAttack(int index)
    {
        _currentAttack = _attacks[index];
        _isAttacking = true;
        _attackDamageApplied = false;
        _attackTimer = 0f;
        _attackCooldownTimers[index] = _currentAttack.Cooldown;
        // 공격 동작 길이 + 후딜만큼 다음 행동을 막는다.
        _globalCooldownTimer = _currentAttack.Duration + _globalAttackCooldown;

        _state = AIState.Attack;
        StopMoving();
        UpdateFacing();   // 공격 시작 순간 타겟을 바라보고, 이후 공격 끝까지 고정
        PlayAnim(_currentAttack.AnimationState);
    }

    private void TickAttack()
    {
        _attackTimer += Time.deltaTime;
        StopMoving();

        // 선딜이 끝나는 순간 데미지 1회 적용.
        if (!_attackDamageApplied && _attackTimer >= _currentAttack.Windup)
        {
            _attackDamageApplied = true;
            ApplyAttackDamage();
        }

        // 공격 동작이 끝나면 종료 — 상태는 다음 Update에서 재판단.
        if (_attackTimer >= _currentAttack.Duration)
        {
            _isAttacking = false;
            _currentAttack = null;
        }
    }

    private void CancelAttack()
    {
        _isAttacking = false;
        _currentAttack = null;
    }

    // 선딜 종료 시점에 호출. 그 사이 플레이어가 사거리를 벗어났으면 빗나감.
    private void ApplyAttackDamage()
    {
        if (_target == null || _currentAttack == null) return;

        Vector2 delta = _target.position - transform.position;
        if (Mathf.Abs(delta.x) > _currentAttack.Range) return;
        if (Mathf.Abs(delta.y) > _attackVerticalTolerance) return;

        if (_targetDamageable == null) CacheTargetComponents();
        if (_targetDamageable == null) return;

        Vector2 knockback = new Vector2(
            _currentAttack.HitVelocity.x * _facingDirection,
            _currentAttack.HitVelocity.y);
        _targetDamageable.TakeDamage(_currentAttack.Damage, knockback);
    }

    // ─── 특별 스킬 ───────────────────────────────────────────────────────

    // 사용 가능한 스킬 프리팹 후보 중 무작위 1개의 인덱스 반환. 없으면 -1.
    // 조건은 프리팹에서 직접 읽는다 (MinPhase/Range). 쿨다운은 보스별 타이머로.
    private int PickSkillIndex()
    {
        if (_skillPrefabs == null || _skillPrefabs.Length == 0 || _target == null) return -1;

        float distanceX = Mathf.Abs(_target.position.x - transform.position.x);
        int phase = _boss != null ? _boss.CurrentPhase : 0;

        int candidateCount = 0;
        for (int i = 0; i < _skillPrefabs.Length; i++)
        {
            BossSkill prefab = _skillPrefabs[i];
            if (prefab == null) continue;
            if (phase < prefab.MinPhase) continue;         // 페이즈 미해금
            if (_skillCooldownTimers[i] > 0f) continue;    // 쿨다운 중
            if (distanceX > prefab.Range) continue;        // 사거리 밖
            _skillPickBuffer[candidateCount++] = i;
        }

        if (candidateCount == 0) return -1;
        return _skillPickBuffer[UnityEngine.Random.Range(0, candidateCount)];
    }

    private void BeginSkill(int index)
    {
        BossSkill prefab = _skillPrefabs[index];
        _skillCooldownTimers[index] = prefab.Cooldown;

        _state = AIState.Idle;
        StopMoving();
        UpdateFacing();   // _facingDirection을 타겟 방향으로 갱신

        // 스킬 프리팹을 보스 위치에 생성하고 보스의 자식으로 둔다 (보스 파괴 시 함께 정리).
        BossSkill instance = Instantiate(prefab, transform.position, Quaternion.identity, transform);

        // 보스가 왼쪽을 보면 스킬도 X 반전 (콜라이더 패턴이 시전 방향을 따르게).
        if (_facingDirection < 0f)
        {
            Vector3 scale = instance.transform.localScale;
            scale.x = -Mathf.Abs(scale.x);
            instance.transform.localScale = scale;
        }

        _runningSkillInstance = instance;
        _skillInProgress = true;

        PlayAnim(prefab.CasterAnimationState);   // 보스는 시전 애니메이션 재생
        instance.Begin();
    }

    // 진행 중인 스킬 인스턴스를 파괴해 즉시 중단 (콜라이더도 함께 사라짐).
    private void CancelRunningSkill()
    {
        if (_runningSkillInstance != null)
            Destroy(_runningSkillInstance.gameObject);
        _runningSkillInstance = null;
        _skillInProgress = false;
    }

    private void TickCooldowns()
    {
        if (_globalCooldownTimer > 0f)
            _globalCooldownTimer -= Time.deltaTime;

        for (int i = 0; i < _attackCooldownTimers.Length; i++)
            if (_attackCooldownTimers[i] > 0f)
                _attackCooldownTimers[i] -= Time.deltaTime;

        for (int i = 0; i < _skillCooldownTimers.Length; i++)
            if (_skillCooldownTimers[i] > 0f)
                _skillCooldownTimers[i] -= Time.deltaTime;
    }

    // ─── 타겟 / 인지 / 방향 ──────────────────────────────────────────────

    private void ResolveTarget()
    {
        if (_target != null)
        {
            if (_targetDamageable == null) CacheTargetComponents();
            return;
        }
        if (!_autoFindPlayer) return;

        PlayerController player = FindFirstObjectByType<PlayerController>();
        if (player == null) return;

        _target = player.transform;
        CacheTargetComponents();
    }

    private void CacheTargetComponents()
    {
        _targetDamageable = _target != null ? _target.GetComponent<IDamageable>() : null;
    }

    // 보스는 한 번 플레이어를 인지하면 계속 추격한다 (인지 해제 없음).
    private void RefreshAggro()
    {
        if (_hasAggro || _target == null) return;

        Vector2 delta = _target.position - transform.position;
        if (Mathf.Abs(delta.x) <= _detectRange && Mathf.Abs(delta.y) <= _detectVerticalRange)
            _hasAggro = true;
    }

    private void UpdateFacing()
    {
        if (_target == null) return;

        float dx = _target.position.x - transform.position.x;
        if (Mathf.Abs(dx) <= 0.05f) return;

        _facingDirection = Mathf.Sign(dx);
        if (_spriteRenderer != null)
            _spriteRenderer.flipX = _facingDirection < 0f;
    }

    private void StopMoving()
    {
        if (_rb == null) return;
        Vector2 v = _rb.linearVelocity;
        v.x = 0f;
        _rb.linearVelocity = v;
    }

    // ─── 상태 / 애니메이션 ───────────────────────────────────────────────

    private void SetState(AIState state)
    {
        _state = state;
        if (state == AIState.Idle) PlayAnim(_idleAnimationState);
        else if (state == AIState.Chase) PlayAnim(_runAnimationState);
        // Attack 상태 애니메이션은 BeginAttack, 스킬 시전 애니메이션은 BeginSkill에서 재생.
    }

    // 같은 State 중복 재생 방지 (Play를 매 프레임 호출하면 애니가 처음으로 리셋됨).
    private void PlayAnim(string state)
    {
        if (_anim == null || string.IsNullOrEmpty(state)) return;
        if (_activeAnimationState == state) return;

        _anim.Play(state);
        _activeAnimationState = state;
    }

    private void OnDrawGizmosSelected()
    {
        Gizmos.color = Color.yellow;
        Gizmos.DrawWireSphere(transform.position, _detectRange);

        Gizmos.color = Color.red;
        if (_attacks != null)
            for (int i = 0; i < _attacks.Length; i++)
                if (_attacks[i] != null)
                    Gizmos.DrawWireSphere(transform.position, _attacks[i].Range);

        Gizmos.color = new Color(1f, 0.4f, 1f);  // 스킬 사거리 = 보라색
        if (_skillPrefabs != null)
            for (int i = 0; i < _skillPrefabs.Length; i++)
                if (_skillPrefabs[i] != null)
                    Gizmos.DrawWireSphere(transform.position, _skillPrefabs[i].Range);
    }
}
