using System;

using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;
using EnemyType = Define.EnemyType;
using Random = UnityEngine.Random;


//EnemyController는 몬스터의 '뇌' 역할을 하며, 상태 머신 패턴을 기반으로 동작하고, 외부에서 데이터를 주입받아 초기화되는 구조로 설계하기
public class EnemyController : MonoBehaviour, IDamageable
{
    // 데미지를 입력하기 위한 클래스 선언 필드
    private Damage _damage;
    // 이동을 하기 위한 클래스 선언 필드
    private Movement_Base _movement;
    // 상태 정보가 담긴 클래스 선언 필드
    private Status_Enemy _status;
    public Status_Enemy Status 
    {
        get { return _status; }
        private set { _status = value;}
    }
    
    [SerializeField] private EnemyType _type = EnemyType.Unknown;
    [SerializeField] private int _expRate = 5;

    public Movement_Base Movement => _movement;
    public EnemyType Type => _type;
    
    private AI_State _currentState;
    public AI_State CurrentState
    {
        get { return _currentState; }
        set
        {
            if (_currentState != null)
                _currentState.Exit();
            _currentState = value;
            
            if (_currentState != null)
                _currentState.Enter();
        }
    }

    [SerializeField] private bool _explose = false;
    private bool _hasExploded = false;
    
    
    private void Awake()
    {
        _movement = gameObject.GetComponent<Movement_Base>();
        _status = gameObject.GetComponent<Status_Enemy>();
        _damage = gameObject.AddComponent<Damage_Melee>();
        _damage._targetlayer = LayerMask.GetMask("Player");
    }

    void Start()
    {
    }

    public void Init(EnemyData data)
    {
        _type = data.E_Type;
        
        if (_damage != null)
        {
            _damage.OnHit -= OnBodyHit;
            _damage.OnHit += OnBodyHit;
        }
    }

    void Update()
    {
        if (CurrentState != null)
            CurrentState.Update();
        _damage?.SetTriggerActive(true);

        if (_explose && !_hasExploded)
        {
            _hasExploded = true;
            OnExplose();
        }
    }
    
    private void OnBodyHit(IDamageable target, Collider collider)
    {
        Debug.Log($"Player Hit! {collider.name}");
    }

    public void TakeDamage(float damage)
    {
        float hp = Status.ApplyDamage(damage);
        if (hp <= 0)
        {
            _explose = true;
        }
        Debug.Log($"피격! 데미지: {damage} / 남은 체력: {hp}");
    }

    private void OnExplose()
    {
        Vector3 currentPosition = transform.position;

        int totalExp = Mathf.RoundToInt(_status.ExpAmount);
        int cubeCount = (totalExp / _expRate) + (totalExp % _expRate > 0 ? 1 : 0);
        // 5/5/5/3 = 18
        // count = 4 
        for (int i = 0; i < cubeCount; i++)
        {
            float amount = Mathf.Min(_expRate, (totalExp - (i * _expRate)));
            
            Vector3 spawnPosition = currentPosition + Random.insideUnitSphere * 2f;
            spawnPosition.y = currentPosition.y;

            GameObject expCube =
                Manager.Resource.Instantiate("Prefabs/Objects/ExpCube", GameObject.Find("@Object").transform);
            expCube.GetComponent<ExpCubeComponent>().SetExpAmount(amount);
            expCube.transform.position = spawnPosition;

        }

        Destroy(gameObject, 0.1f);
        
    }
}


/*
 * 행동 패턴
 * - 종류 : Idle(대기), Patrol(순찰), Chase(추적), Run(도망), Return(귀환), Hide(숨기), Fight(싸우기)
 * 1. Idle : 제자리에서 대기
 * 2. Patrol : 지정된 경로를 따라 순찰
 * 3. Chase : 플레이어를 발견하면 추적
 * 4. Run : (옵션) 체력이 너무 낮으면 도망
 * 5. Return : 일정 시간 동안 플레이어를 찾지 못하면 원래 위치로 귀환
 * 6. Hide : 플레이어의 시야에서 벗어나 숨기
 * 7. Fight : 플레이어와 일정 거리 내에 들어오면 싸우기
 * - 행동 전환
 * 1. Idle -> Patrol : 일정 시간 후
 * 2. Idle/Patrol -> Chase : 플레이어 발견 시
 *   2.1. 플레이어 발견 조건 : 시야각, 거리, 장애물 유무 등
 * 3. Idle/Patrol/Chase -> Run : (옵션) 체력이 일정 이하로 떨어지면
 * 4. Idle/Patrol/Chase/Run -> Fight : 플레이어와 일정 거리 내에 들어오면
 * 5. Patrol -> Idle : 일정 시간 동안 움직이지 않으면
 * 6. Patrol/Chase/Run/Fight -> Return : 플레이어를 일정 시간 동안 찾지 못하면
 * 7. Patrol/Chase/Run/Fight -> Hide : 플레이어의 시야에서 벗어나면
*/