using System;
using System.Collections;
using System.Collections.Generic;
using Animation;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;

public partial class PlayerController : MonoBehaviour, IDamageable
{
    #region Enum 정의
    enum AnimatorParam
    {
        speed,
        atk_speed,
        attack,
        run,
    }
    
    enum PlayerBehavior
    {
        Idle,
        Move,
        Attack,
        Die
    }

    // rigidbody와 NavMeshAgent를 함께 사용할 때의 물리엔진 상 문제가 생겨서 그거를 구분하기 위한 부분
    // NavMeshAgent가 뇌, rigidbody가 몸 역할을 하게 됨
    public enum ControlMode
    {
        Player,
        AI
    }
    #endregion
    
    // 이벤트
    public event Action<string, float, float> OnExpChanged;
    
    
    // 상태 정보
    private Status_Player _status;
    public Status_Player Status
    {
        get { return _status; }
        private set { _status = value;}
    }
    
    // 획득
    private MagnetComponent _magnet;
    
    // 이동 관련
    private float _runTriggerRatio = 0.6f;
    private float _rotationSpeed = 10f;
    private ControlMode _controlMode = ControlMode.Player;
    
    // 공격 관련
    private NavMeshAgent _agent;
    private Rigidbody _rigidbody;
    public bool _isAttack = false;
    private Damage _weaponDamage;
    [SerializeField] private Transform _weaponSocket;
    [SerializeField] private Transform _shieldSocket;
    
    // 애니메이터 관련
    private AnimatorManager<AnimatorParam> _mAnimator;
    private PlayerBehavior _behavior = PlayerBehavior.Idle;
    private PlayerBehavior Behavior
    {
        get { return _behavior; }
        set
        {
            _behavior = value;
            switch (_behavior)
            {
                case PlayerBehavior.Die:
                case PlayerBehavior.Idle:
                    _mAnimator.SetValue(AnimatorParam.speed, 0);
                    break;
                case PlayerBehavior.Move:
                    _mAnimator.SetValue(AnimatorParam.attack, false);
                    break;
                case PlayerBehavior.Attack:
                    _mAnimator.SetValue(AnimatorParam.attack, true);
                    break;
            }
        }
    }

    private void Awake()
    {
        _mAnimator = new AnimatorManager<AnimatorParam>(GetComponent<Animator>());
        _agent = gameObject.GetComponent<NavMeshAgent>();
        _rigidbody = gameObject.GetComponent<Rigidbody>();
        _status = gameObject.GetOrAddComponent<Status_Player>();
        _magnet = gameObject.GetComponentInChildren<MagnetComponent>();
        
        
        if(_agent != null) _agent.updateRotation = false;
    }

    void Start()
    {
        _status.Data = Manager.Data.LoadSingle<PlayerDataLoader, Data_Status_Player>("Data/PlayerData");
        SetAnimator();

        EquipWeapon(_weaponSocket, "Prefabs/Equipment/Weapon");
        // EquipWeapon(_shieldSocket, "Prefabs/Equipment/Shield");

        SubscribeAction();
        
        
    }
    
    void SubscribeAction()
    {
        Manager.Input.MoveAction -= OnMove;
        Manager.Input.MoveAction += OnMove;
        
        Manager.Input.RegisterAction("Btn_Attack", OnAttack);
        
        _magnet.OnGetExp -= OnGetExp;
        _magnet.OnGetExp += OnGetExp;
        
        SetEXPBar();
    }

    // 애니메이터 세팅 (지금은 한 줄 뿐이지만 후에 더 추가될 수도)
    void SetAnimator()
    {
        if (_status != null)
        {
            _mAnimator.SetValue(AnimatorParam.atk_speed, _status.AtkSpeed);
        }
    }

    // --- 매 프레임 실행 ---
    void Update()
    {
        PlayerMovement();
    }

    private void PlayerMovement()
    {
        if (_controlMode == ControlMode.AI)
        {
            if(_agent.pathPending || !_agent.hasPath) return;
            _rigidbody.linearVelocity = Vector3.zero;

            // 회전
            if (_agent.desiredVelocity.sqrMagnitude > 0.1f)
            {
                Quaternion targetRotation = Quaternion.LookRotation(_agent.desiredVelocity.normalized);
                transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * _rotationSpeed);
            }

            if (_agent.remainingDistance <= _agent.stoppingDistance)
            {
                _rigidbody.linearVelocity = Vector3.zero;
                SetControlMode(ControlMode.Player);
            }
        }
    }
    public void SetControlMode(ControlMode mode)
    {
        _controlMode = mode;
        
        switch (_controlMode)
        {
            case ControlMode.Player:
                if(_agent != null) _agent.enabled = false;
                _rigidbody.isKinematic = false;
                _rigidbody.linearVelocity = Vector3.zero;
                break;
            case ControlMode.AI:
                
                _rigidbody.isKinematic = true;
                _rigidbody.linearVelocity = Vector3.zero;
                if (_agent != null) _agent.enabled = true;
                break;
        }
    }

    #region Navi Event
    void OnInput(Define.InputEvent evt)
    {
        switch (evt)
        {
            case Define.InputEvent.Click:
                break;
            case Define.InputEvent.Down:
                break;
            case Define.InputEvent.Up:
                break;
            case Define.InputEvent.Press:
                break;
        }
    }
    
    public void NavigateTo(Vector3 target)
    {
        SetControlMode(ControlMode.AI);
        if (_agent != null)
        {
            _agent.isStopped = false; // 목적지 설정 전 에이전트가 멈춰있지 않도록 합니다.
            _agent.SetDestination(target);
            _agent.speed = _status.MoveSpeed;
        }
    }
    #endregion

    
    void EquipWeapon(Transform transform, string path)
    {
        GameObject newParts = Manager.Resource.Instantiate($"{path}");
        Damage damageScript = newParts.GetComponent<Damage>();
        // damageScript._targetlayer = (1<< 11) | (1 << 12);
        newParts.transform.SetParent(transform);
        newParts.transform.localPosition = Vector3.zero;
        newParts.transform.localRotation = Quaternion.identity;
        newParts.transform.localScale = Vector3.one;
        
        _weaponDamage = newParts.GetComponentInChildren<Damage>();
        if (_weaponDamage != null)
        {
            _weaponDamage.OnHit -= OnWeaponHit;
            _weaponDamage.OnHit += OnWeaponHit;
        }
    }
    
    
    
    #region Action Event
    private void OnMove(Vector2 direction)
    {
        SetControlMode(ControlMode.Player);
        
        float magnitude = direction.magnitude;
        bool isRun = direction.magnitude > _runTriggerRatio ? true : false;
        float speed = 0f;
        
        // 입력이 거의 없을 때
        if (magnitude < 0.1f) speed = 0f;
        // 걷기 구간일 때
        else if (magnitude <= _runTriggerRatio) speed = Mathf.Lerp(0, _status.MoveSpeed, (magnitude/_runTriggerRatio));
        // 달리기 구간일 때
        else
        {
            float runPercentage = (magnitude - _runTriggerRatio) / (1.0f - _runTriggerRatio);
            speed = Mathf.Lerp(_status.MoveSpeed, _status.MoveSpeed * 2.0f, runPercentage);
        }
        
        _agent.speed = speed;
        _mAnimator.SetValue(AnimatorParam.run, isRun);
        _mAnimator.SetValue(AnimatorParam.speed , speed);

        if (magnitude < 0.1f)
        {
            _rigidbody.linearVelocity = Vector3.zero;
            return;
        }
        
        Vector3 camForward = Camera.main.transform.forward;
        Vector3 camRight = Camera.main.transform.right;
        
        camForward.y = 0;
        camRight.y = 0;
        camForward.Normalize();
        camRight.Normalize();
        Vector3 moveDir = (camForward * direction.y + camRight * direction.x).normalized;
        
        if (moveDir != Vector3.zero)
        {
            Quaternion targetRotation = Quaternion.LookRotation(moveDir);
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, _rotationSpeed * Time.deltaTime);
        }
        
        _rigidbody.linearVelocity = transform.forward * speed;
    }
    
    private void OnWeaponHit(IDamageable target, Collider collider)
    {
        
        // 적 캐릭터인지 확인
        // var enemy = target.GetComponent<EnemyController>();
        if (collider.gameObject.layer == LayerMask.NameToLayer("Enemy"))
        {
            Debug.Log($"Enemy Hit! {collider.name}");
        }
        else
        {
            Debug.Log($"other Hit! {collider.name}");
        }
    }

    private void OnAttack()
    {
        if (!_isAttack)
        {
            _isAttack = true;
            Behavior = PlayerBehavior.Attack;
        }
    }

    private void OnSkill(int index)
    {
        
    }
    
    private void OnGetExp(float amount)
    {
        if (_status != null)
        {
            _status.ApplyExp(amount);
            SetEXPBar();
            
            Debug.Log($"Player Exp: {amount} / {_status.Exp}");
        }
    }

    private void SetEXPBar()
    {
        EventBus.Raise(new PlayerExpEvent
        {
            Level = _status.Level.ToString(), 
            CurrentExp = _status.Exp,
            MaxExp = _status.MaxExp
        });
    }
    
    #endregion
    
    #region Interface 구현
    public void TakeDamage(float damage)
    { 
        float hp = Status.ApplyDamage(damage);
        Debug.Log($"적에게 피격! 데미지: {damage} / 남은 체력: {hp}");
    }
    
    #endregion
    
    private void OnDestroy()
    {
        
    }

    
}

// 애니메이션의 이벤트 함수 부분
public partial class PlayerController {
    public void Hit()
    {
        _mAnimator.SetValue(AnimatorParam.attack, false);
        Debug.Log("Knight Hit!");
    }
    
    public void FootR()
    {
        
    }

    public void FootL()
    {
        
    }

    public void EnableCollider()
    {
        _weaponDamage?.SetTriggerActive(true);
    }

    public void DisableCollider()
    {
        _weaponDamage?.SetTriggerActive(false);
    }
    public void EndAttack()
    {
        if (_isAttack)
        {
            _isAttack = false;
            _mAnimator.SetValue(AnimatorParam.attack, _isAttack);
            _weaponDamage?.SetTriggerActive(false);
            Behavior = PlayerBehavior.Idle;
        }
    }

}
