using System;
using System.Collections.Generic;
using UnityEngine;

public class SpawnController : MonoBehaviour
{
    private Dictionary<string, EnemyData> _enemyDatas;
    private Dictionary<string, GameObject> _prototypes = new Dictionary<string, GameObject>();
    private readonly List<GameObject> _spawned = new();
    
    [SerializeField] private string _enemyPrefabPath; // 스폰할 프리팹
    [SerializeField] private string _enemyDataPath; // 스폰할 프리팹
    [SerializeField] private LayerMask _spawnedTargetLayers; // 스포너 Inspector에서 설정
    [SerializeField] private LayerMask _spawnedObstacleLayers; // 스포너 Inspector에서 설정
    
    private Transform _prototypeRoot; // 계층 관리용
    
    int monsterCount = 0;

    public string EnemyPrefabPath { get { return _enemyPrefabPath; } set { _enemyPrefabPath = value; }}
    public string EnemyDataPath { get { return _enemyDataPath; } set { _enemyDataPath = value; }}
    
    void Awake()
    {
        var root = new GameObject("EnemyPrototypes");
        root.SetActive(false);
        _prototypeRoot = root.transform;
    }

    private void Start()
    {
        if (string.IsNullOrEmpty(EnemyPrefabPath) || string.IsNullOrEmpty(EnemyDataPath))
            throw new ArgumentNullException("EnemyPrefabPath or EnemyDataPath is null or empty");
        
        _enemyDatas =
            Manager.Data.LoadToDict<EnemyDataLoader, string, EnemyData>(EnemyDataPath, (enemy) => enemy.name);
        
        CreateEnemyPrototype();
    }

    void Update()
    {
        float radius = 2.0f;
        
        for (; monsterCount < 5; monsterCount++)
        {
            float angle = monsterCount * Mathf.PI * 2 / 5;
            Vector3 pos = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * radius + new Vector3(0, 0, 10);
            SpawnFromProtoType("Test_Enemy_1", pos);
        }
    }

    void CreateEnemyPrototype()
    {
        foreach (var enemyData in _enemyDatas)
        {
            string key = enemyData.Key;
            EnemyData data = enemyData.Value;

            GameObject enemy = Manager.Resource.Instantiate(EnemyPrefabPath);
            enemy.name = $"{key}_Prototype";
            enemy.transform.SetParent(_prototypeRoot, worldPositionStays: false);
            enemy.SetActive(false);
            
            if(!enemy.TryGetComponent<EnemyController>(out _)) enemy.AddComponent<EnemyController>();
            
            var status = enemy.GetComponent<Status_Enemy>();
            if (status == null) status = enemy.AddComponent<Status_Enemy>();
            status.Data = data.status;
            // status = data.status;
            // status.CopyFrom(statusData);
            
            _prototypes[key] = enemy;
        }
    }

    public GameObject SpawnFromProtoType(string key, Vector3 position, Quaternion? rotation = null)
    {
        if(!_prototypes.TryGetValue(key, out GameObject prototype)|| prototype == null)
        {
            Debug.LogError($"SpawnFromProtoType Failed! : {key}");
            return null;
        }
        
        var rot = rotation ?? Quaternion.identity;
        GameObject clone = Instantiate(prototype, position, rot);
        clone.name = $"{key}";
        clone.SetActive(true);
        _spawned.Add(clone);
        return clone;
    }
    
    // 오버로드: 회전 생략
    // public GameObject SpawnFromPrototype(string key, Vector3 position) => SpawnFromPrototype(key, position, null);


    public void Despawn(GameObject go)
    {
        if (go == null) return;
        _spawned.Remove(go);
        Destroy(go);
    }
    public void DespawnAll()
    {
        for (int i = _spawned.Count - 1; i >= 0; i--)
        {
            Despawn(_spawned[i]);
        }
        _spawned.Clear();
    }
    
    
    
    // private static void CopyStatusValues(Status_Enemy src, Status_Enemy dst)
    // {
    //     if (src == null || dst == null) return;
    //
    //     var type = typeof(Status_Enemy);
    //
    //     foreach (var f in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
    //     {
    //         if (f.IsInitOnly || f.IsLiteral) continue;
    //         if (typeof(Delegate).IsAssignableFrom(f.FieldType)) continue;
    //         f.SetValue(dst, f.GetValue(src));
    //     }
    //
    //     foreach (var p in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
    //     {
    //         if (!p.CanRead || !p.CanWrite) continue;
    //         if (p.GetIndexParameters().Length > 0) continue;
    //         try { p.SetValue(dst, p.GetValue(src)); } catch { }
    //     }
    // }

    
}
