
using TMPro;
using UnityEngine;


public enum ActionDecisionState
{
    NoAction,
    ActionSelected,
    ActionExecuted,
    EnemyAction
}

[System.Serializable]
public class CharacterActionData
{
    public ActionDecisionState state = ActionDecisionState.NoAction;
    public Vector3 targetPosition;
    public GameObject targetEnemy;
    public bool hasTarget => targetEnemy != null || targetPosition != Vector3.zero;

    public void Reset()
    {
        state = ActionDecisionState.NoAction;
        targetPosition = Vector3.zero;
        targetEnemy = null;
    }

    public void SetMoveTarget(Vector3 position)
    {
        targetPosition = position;
        targetEnemy = null;
        state = ActionDecisionState.ActionSelected;
    }

    public void SetAttackTarget(GameObject enemy)
    {
        targetEnemy = enemy;
        targetPosition = Vector3.zero;
        state = ActionDecisionState.ActionSelected;
    }
}

public abstract class Character : MonoBehaviour
{
    private string characterName;
    private int maxHealth;
    private int currentHealth;
    private int attack;
    private int constitution;
    private int dexterity;
    private int wisdom;
    private Sprite characterSprite;
    private int level;
    private int experiencePoints;
    private int experienceToLevelUp;
    private int initModifier;
    private int damageModifier;
    private int spellModifier;
    private int movementSpeed;
    private int armorClass;
    private bool isDead = false;
    private bool isTargetable = true;

    private Bank bank;
    private Inventory inventory;
    private TextMeshProUGUI nameText;

    // Health bar components
    private UnityEngine.UI.Slider healthSlider;
    private Canvas healthBarCanvas;

    // Add action system components
    [Header("Action System")]
    public CharacterActionData actionData = new CharacterActionData();

    [Header("Visual Feedback Settings")]
    public Color noActionColor = Color.yellow;
    public Color actionSelectedColor = Color.green;
    public Color normalColor = Color.white;
    public float outlineWidth = 0.1f;

    // Visual feedback components
    private Renderer characterRenderer;
    private Material characterMaterial;
    private Color originalColor;
    private GameObject outlineObject;

    public string CharacterName
    {
        get => characterName; set
        {
            characterName = value;
            UpdateNameDisplay();
        }
    }
    public int MaxHealth { get => maxHealth; set => maxHealth = value; }
    public int CurrentHealth { get => currentHealth; set => currentHealth = value; }
    public int Attack { get => attack; set => attack = value; }
    public int Constitution { get => constitution; set => constitution = value; }
    public int Dexterity { get => dexterity; set => dexterity = value; }
    public int Wisdom { get => wisdom; set => wisdom = value; }
    public Sprite CharacterSprite { get => characterSprite; set => characterSprite = value; }
    public int Level { get => level; set => level = value; }
    public int ExperiencePoints { get => experiencePoints; set => experiencePoints = value; }
    public int ExperienceToLevelUp { get => experienceToLevelUp; set => experienceToLevelUp = value; }
    public int InitModifier { get => initModifier; set => initModifier = value; }
    public int DamageModifier { get => damageModifier; set => damageModifier = value; }
    public int SpellModifier { get => spellModifier; set => spellModifier = value; }
    public int MovementSpeed { get => movementSpeed; set => movementSpeed = value; }
    public int ArmorClass { get => armorClass; set => armorClass = value; }
    public bool IsDead { get => isDead; }
    public bool IsTargetable { get => isTargetable; }

    protected Weapon spawnedWeapon;

    public Weapon Weapon { get => spawnedWeapon; set => spawnedWeapon = value; }

    public abstract Character Spawn(int count);

    public abstract Weapon GetWeapon();

    public Character()
    {
    }

    void Start()
    {
        InitializeStats();
        // SpawnAndEquipWeapon();
        InitializeActionSystem();
        Debug.Log($"Character Start() completed for {CharacterName}");
        healthSlider = GetComponentInChildren<UnityEngine.UI.Slider>();
    }

    protected virtual void InitializeStats()
    {
        // Override in subclasses to set character stats
    }

    public Weapon GetEquippedWeapon()
    {
        return spawnedWeapon;
    }
    public virtual void SpawnAndEquipWeapon()
    {
        Debug.Log($"SpawnAndEquipWeapon called for {CharacterName}");
        Weapon weaponPrefab = GetWeapon();
        Debug.Log($"GetWeapon returned: {(weaponPrefab != null ? weaponPrefab.name : "null")}");

        if (weaponPrefab != null)
        {
            GameObject weaponInstance = Instantiate(weaponPrefab.gameObject);
            weaponInstance.transform.SetParent(this.transform, false);
            Debug.Log($"Instantiated weapon: {weaponInstance.name}");

            spawnedWeapon = weaponInstance.GetComponent<Weapon>();
            Debug.Log($"spawnedWeapon component: {(spawnedWeapon != null ? spawnedWeapon.GetType().Name : "null")}");

            if (spawnedWeapon != null)
            {
                // Set the wielder reference directly to avoid timing issues
                spawnedWeapon.SetWielder(this);
                Debug.Log($"{CharacterName} equipped {spawnedWeapon.weaponName}");
                // Position the weapon appropriately (you may want to customize this)
                PositionWeapon(weaponInstance);
            }
            else
            {
                Debug.LogError($"Weapon prefab for {CharacterName} doesn't have a Weapon component!");
                Destroy(weaponInstance);
            }
        }
        else
        {
            Debug.Log($"{CharacterName} no weapon prefab, trying direct creation...");
            CreateDirectWeapon();
        }
    }

    protected virtual Weapon CreateDirectWeapon()
    {
        Debug.LogWarning($"{CharacterName} - CreateDirectWeapon not implemented in subclass!");
        return null;
    }

    // Virtual method to position the weapon - can be overridden by specific character types
    protected virtual void PositionWeapon(GameObject weaponInstance)
    {
        // Default positioning - you can customize this based on your character setup
        weaponInstance.transform.localPosition = Vector3.zero;
        weaponInstance.transform.localRotation = Quaternion.identity;
        weaponInstance.transform.localScale = Vector3.one; // Ensure proper scale

        // Optional: Look for specific attachment points
        Transform weaponAttachPoint = transform.Find("WeaponAttachPoint");
        if (weaponAttachPoint != null)
        {
            weaponInstance.transform.SetParent(weaponAttachPoint, false);
            weaponInstance.transform.localPosition = Vector3.zero;
            weaponInstance.transform.localRotation = Quaternion.identity;
            Debug.Log($"Weapon attached to {weaponAttachPoint.name}");
        }
        else
        {
            // If no specific attach point, just position relative to character
            weaponInstance.transform.localPosition = new Vector3(0.5f, 0, 0); // Slightly to the right
            Debug.Log($"Weapon positioned at default location relative to {CharacterName}");
        }
    }

    void Awake()
    {
        nameText = GetComponentInChildren<TextMeshProUGUI>();
        if (nameText == null)
        {
            Debug.LogWarning($"No TextMeshProUGUI component found in children of {gameObject.name}");
        }

        // Initialize visual feedback system
        InitializeVisualFeedback();
        UpdateNameDisplay();
    }
    // Initialize visual feedback components
    private void InitializeVisualFeedback()
    {
        characterRenderer = GetComponent<Renderer>();
        if (characterRenderer != null)
        {
            // Create a unique material instance to avoid modifying shared materials
            characterMaterial = new Material(characterRenderer.material);
            characterRenderer.material = characterMaterial;
            originalColor = characterMaterial.color;
        }
        else
        {
            Debug.LogWarning($"No Renderer found on {gameObject.name}. Visual feedback will not work.");
        }

        // Ensure we have a collider for mouse detection
        Collider col = GetComponent<Collider>();
        if (col == null)
        {
            col = gameObject.AddComponent<CapsuleCollider>();
            Debug.Log($"Added CapsuleCollider to {gameObject.name} for mouse detection");
        }
    }
    private void UpdateNameDisplay()
    {
        if (nameText != null && !string.IsNullOrEmpty(characterName))
        {
            nameText.text = characterName;
        }
    }

    public void RefreshNameDisplay()
    {
        UpdateNameDisplay();
    }

    public virtual float GetAttackRange()
    {
        return spawnedWeapon != null ? spawnedWeapon.Range : 1.0f; // Default range if no weapon is equipped
    }

    private void InitializeActionSystem()
    {
        actionData.Reset();
        SetVisualState(ActionDecisionState.NoAction);
    }

    public void SetVisualState(ActionDecisionState state)
    {
        if (characterRenderer == null) return;

        switch (state)
        {
            case ActionDecisionState.NoAction:
                ShowNoActionState();
                break;
            case ActionDecisionState.ActionSelected:
                ShowActionSelectedState();
                break;
            default:
                ShowNormalState();
                break;
        }
    }

    private void ShowNoActionState()
    {
        if (characterMaterial != null)
            characterMaterial.color = noActionColor;
        CreateOutline();
    }

    private void ShowActionSelectedState()
    {
        if (characterMaterial != null)
            characterMaterial.color = actionSelectedColor;
        RemoveOutline();
    }

    private void ShowNormalState()
    {
        if (characterMaterial != null)
            characterMaterial.color = originalColor;
        RemoveOutline();
    }

    private void CreateOutline()
    {
        if (outlineObject != null) return;

        outlineObject = new GameObject("Outline");
        outlineObject.transform.SetParent(transform);
        outlineObject.transform.localPosition = Vector3.zero;
        outlineObject.transform.localScale = Vector3.one * (1f + outlineWidth);

        // For 3D characters, we'll create a simple colored outline using a MeshRenderer
        MeshFilter meshFilter = outlineObject.AddComponent<MeshFilter>();
        MeshRenderer outlineRenderer = outlineObject.AddComponent<MeshRenderer>();

        // Copy the mesh from the character
        MeshFilter characterMesh = GetComponent<MeshFilter>();
        if (characterMesh != null)
        {
            meshFilter.mesh = characterMesh.mesh;
        }

        // Create a simple black material for the outline
        Material outlineMaterial = new Material(Shader.Find("Standard"));
        outlineMaterial.color = Color.black;
        outlineRenderer.material = outlineMaterial;

        // Set rendering order to appear behind the character
        outlineRenderer.sortingOrder = -1;
    }

    private void RemoveOutline()
    {
        if (outlineObject != null)
        {
            DestroyImmediate(outlineObject);
            outlineObject = null;
        }
    }


    public void ExecuteAction()
    {
        Debug.Log($"=== ExecuteAction called for {CharacterName} ===");
        Debug.Log($"Action state: {actionData.state}");
        Debug.Log($"Has target enemy: {actionData.targetEnemy != null}");
        Debug.Log($"Target enemy name: {(actionData.targetEnemy != null ? actionData.targetEnemy.name : "none")}");

        if (actionData.state != ActionDecisionState.ActionSelected)
        {
            Debug.Log($"Action not selected, returning. State: {actionData.state}");
            return;
        }

        if (actionData.targetEnemy != null)
        {
            Debug.Log($"{CharacterName} executing attack on {actionData.targetEnemy.name}");

            // Get equipped weapon and perform attack
            Debug.Log($"Getting equipped weapon for {CharacterName}...");
            Debug.Log($"spawnedWeapon is: {(spawnedWeapon != null ? spawnedWeapon.GetType().Name : "null")}");
            Weapon equippedWeapon = GetEquippedWeapon();
            Debug.Log($"GetEquippedWeapon returned: {(equippedWeapon != null ? equippedWeapon.GetType().Name : "null")}");

            if (equippedWeapon != null)
            {
                Debug.Log($"Using weapon: {equippedWeapon.weaponName}");
                equippedWeapon.Attack(actionData.targetEnemy);

                Character targetCharacter = actionData.targetEnemy.GetComponent<Character>();
                if (targetCharacter != null && targetCharacter.IsDead)
                {
                    actionData.state = ActionDecisionState.ActionExecuted;
                    SetVisualState(actionData.state);
                }
            }
            else
            {
                Debug.LogError($"{CharacterName} has no weapon equipped for attack!");
                Debug.LogError($"spawnedWeapon field is: {(spawnedWeapon != null ? "not null" : "null")}");
                Debug.LogError($"Weapon property is: {(Weapon != null ? "not null" : "null")}");
            }
        }
        else if (actionData.targetPosition != Vector3.zero)
        {
            Debug.Log($"{CharacterName} moves to {actionData.targetPosition}");
            // Add your movement logic here

            actionData.state = ActionDecisionState.ActionExecuted;
            SetVisualState(actionData.state);
        }
    }

    public bool HasActionSelected()
    {
        return actionData.state == ActionDecisionState.ActionSelected;
    }

    public bool IsActionComplete()
    {
        // If action is already executed or no action, it's complete
        if (actionData.state != ActionDecisionState.ActionSelected) return true;

        if (actionData.targetEnemy != null)
        {
            // Check if we're within attack range of the target
            float distance = Vector3.Distance(transform.position, actionData.targetEnemy.transform.position);
            float attackRange = GetAttackRange();
            return distance <= attackRange;
        }
        else if (actionData.targetPosition != Vector3.zero)
        {
            // Check if we've reached the movement target using horizontal distance
            Vector3 currentPos = transform.position;
            Vector3 targetPos = actionData.targetPosition;
            Vector2 currentPos2D = new Vector2(currentPos.x, currentPos.z);
            Vector2 targetPos2D = new Vector2(targetPos.x, targetPos.z);
            float horizontalDistance = Vector2.Distance(currentPos2D, targetPos2D);
            return horizontalDistance <= 1.2f; // Arrival threshold
        }

        return true; // No target means completed
    }

    public void ResetAction()
    {
        actionData.Reset();
        SetVisualState(actionData.state);
    }

    public void TakeDamage(int damage)
    {
        if (isDead) return;

        currentHealth -= damage;
        Debug.Log($"{CharacterName} takes {damage} damage. Health: {currentHealth}/{maxHealth}");

        // Update health bar
        UpdateHealthBar();

        if (currentHealth <= 0)
        {
            Die();
        }
    }

    // Debug method to test attacks manually
    public void DebugAttack(GameObject target)
    {
        Weapon equippedWeapon = GetEquippedWeapon();
        if (equippedWeapon != null)
        {
            Debug.Log($"DEBUG: {CharacterName} manually attacking {target.name}");
            equippedWeapon.Attack(target);
        }
        else
        {
            Debug.LogError($"DEBUG: {CharacterName} has no weapon equipped!");
        }
    }

    private void Die()
    {
        isDead = true;
        isTargetable = false;
        currentHealth = 0;

        gameObject.SetActive(false); // Disable the character GameObject
        characterRenderer.enabled = false;

        // Make character gray
        if (characterMaterial != null)
        {
            characterMaterial.color = Color.gray;
        }

        // Update health bar to show death
        UpdateHealthBar();

        Debug.Log($"{CharacterName} has died!");
    }

    private void UpdateHealthBar()
    {
        if (healthSlider != null)
        {
            healthSlider.value = currentHealth;
            healthSlider.maxValue = maxHealth;

            // Change color based on health percentage
            UnityEngine.UI.Image fillImage = healthSlider.fillRect.GetComponent<UnityEngine.UI.Image>();
            if (fillImage != null)
            {
                float healthPercent = (float)currentHealth / maxHealth;
                if (healthPercent > 0.6f)
                    fillImage.color = Color.green;
                else if (healthPercent > 0.3f)
                    fillImage.color = Color.yellow;
                else
                    fillImage.color = Color.red;
            }

            Debug.Log($"Updated health bar for {CharacterName}: {currentHealth}/{maxHealth}");
        }
    }


}