using UnityEngine;
using System.Collections;

public class SimpleBow : Weapon
{
    [Header("Bow Settings")]
    public GameObject arrowPrefab; // Assign arrow prefab in inspector
    public WeaponItem weaponItemData; // Reference to the ScriptableObject data

    public SimpleBow() : base()
    {
        weaponName = "Simple Bow";
        description = "A basic bow for shooting arrows.";
        attackSpeed = 2.0f; // Example: 2 second between shots
        weaponModel = null; // Assign a 3D model if available
        baseWeaponModifier = weaponModifier;
    }

    public override int MinDamage => weaponItemData != null ? weaponItemData.minDamage : 1;

    public override int MaxDamage => weaponItemData != null ? weaponItemData.maxDamage : 6;

    public override int Range => weaponItemData != null ? weaponItemData.range : 100;

    public override int WeaponModifier { get => weaponModifier; set => weaponModifier = value; }


    public int closeRangePenalty = 3; // Penalty for close
    public int closeRange = 5; // Close range threshold in units

    /// <summary>
    /// Initialize this weapon from a WeaponItem ScriptableObject
    /// </summary>
    /// <param name="itemData">The WeaponItem data to use</param>
    public void InitializeFromItem(WeaponItem itemData)
    {
        if (itemData == null) return;

        weaponItemData = itemData;
        weaponName = itemData.itemName;
        description = itemData.description;
        attackSpeed = itemData.attackSpeed;
        weaponModifier = itemData.weaponModifier;
        baseWeaponModifier = itemData.weaponModifier;
        weaponModel = itemData.model3D;

        // Set arrow prefab if provided in the item data
        if (itemData.arrowPrefab != null)
        {
            arrowPrefab = itemData.arrowPrefab;
        }

        Debug.Log($"SimpleBow initialized from item data: {weaponName}");
    }


    protected override IEnumerator PerformAttackSequence(Character target)
    {
        isAttacking = true;
        Debug.Log($"{Wielder.CharacterName} begins attacking {target.CharacterName} with {weaponName} (attack speed: {attackSpeed}s)");

        // Wait for the attack speed duration
        yield return new WaitForSeconds(attackSpeed);

        // Check if target is still in range after attack speed delay
        if (!IsInRange(Wielder.transform.position, target.transform.position))
        {
            Debug.Log($"{target.CharacterName} moved out of range before {Wielder.CharacterName}'s attack completed!");
            isAttacking = false;
            yield break;
        }

        // Check if target is still targetable (not dead)
        if (!target.IsTargetable)
        {
            Debug.Log($"{target.CharacterName} is no longer targetable!");
            isAttacking = false;
            yield break;
        }

        if (Vector3.Distance(Wielder.transform.position, target.transform.position) < closeRange)
        {
            Debug.Log($"target {target.CharacterName} is too close for {Wielder.CharacterName} to use {weaponName} efficiently, getting a penalty of {closeRangePenalty} to the attack roll.");
            WeaponModifier = baseWeaponModifier - closeRangePenalty;
        }

        // Perform hit calculation (d20 + weapon modifier vs target armor class)
        int d20Roll = Random.Range(1, 21);
        int attackRoll = d20Roll + WeaponModifier;
        bool hits = attackRoll >= target.ArmorClass;

        int healthBefore = target.CurrentHealth;
        int damageDealt = hits ? GetDamage() : 0;

        Debug.Log($"=== BOW ATTACK DEBUG ===");
        Debug.Log($"Attacker: {Wielder.CharacterName} with {weaponName}");
        Debug.Log($"Target: {target.CharacterName}");
        Debug.Log($"D20 Roll: {d20Roll} + Weapon Modifier: {WeaponModifier} = Attack Roll: {attackRoll}");
        Debug.Log($"Target AC: {target.ArmorClass}");
        Debug.Log($"Target Health Before: {healthBefore}/{target.MaxHealth}");

        if (hits)
        {
            Debug.Log($"HIT! Arrow will deal {damageDealt} damage when it reaches target");
        }
        else
        {
            Debug.Log($"MISS! {attackRoll} < {target.ArmorClass} - Arrow will miss target");
        }

        // Spawn arrow projectile
        SpawnArrow(target, hits, damageDealt);

        isAttacking = false;
    }

    private void SpawnArrow(Character target, bool willHit, int damage)
    {
        if (arrowPrefab == null)
        {
            Debug.LogError($"Arrow prefab not assigned to {weaponName}!");
            // Fallback to direct damage application
            if (willHit)
            {
                target.TakeDamage(damage);
            }
            return;
        }

        // Calculate arrow spawn position (slightly in front of wielder)
        Vector3 spawnPosition = Wielder.transform.position + Wielder.transform.forward * 0.5f + Vector3.up * 1.0f;

        // Instantiate arrow
        GameObject arrowInstance = Instantiate(arrowPrefab, spawnPosition, Quaternion.identity);

        // Try to get Arrow component, if not found, add it
        Arrow arrowScript = arrowInstance.GetComponent<Arrow>();
        if (arrowScript == null)
        {
            Debug.LogError($"The arrow prefab '{arrowPrefab.name}' is missing the 'Arrow' script component. Destroying spawned arrow.", arrowPrefab);
            Destroy(arrowInstance);
            if (willHit)
            {
                // Fallback to direct damage application
                target.TakeDamage(damage);
            }
            return;
        }

        if (willHit)
        {
            // Raycast to find hit point on collider
            Vector3 targetPosition;

            Collider targetCollider = target.GetComponent<Collider>();
            if (targetCollider != null)
            {
                // Aim at the center of the collider
                Vector3 center = targetCollider.bounds.center;
                Vector3 extents = targetCollider.bounds.extents;

                // Add a small random offset within the collider's bounds for variety
                Vector3 randomOffset = new Vector3(
                    Random.Range(-extents.x * 0.7f, extents.x * 0.7f),
                    Random.Range(-extents.y * 0.7f, extents.y * 0.7f),
                    Random.Range(-extents.z * 0.7f, extents.z * 0.7f)
                );

                targetPosition = center + randomOffset;
            }
            else
            {
                // Fallback: use transform position
                targetPosition = target.transform.position + Vector3.up * 0.5f; // Aim roughly at chest height
            }

            Vector3 direction = (targetPosition - spawnPosition).normalized;
            RaycastHit hit;
            Vector3 hitPoint = targetPosition; // fallback to center/randomized

            if (targetCollider != null && targetCollider.Raycast(new Ray(spawnPosition, direction), out hit, 100f))
            {
                hitPoint = hit.point;
                arrowScript.Initialize(spawnPosition, hitPoint, target, damage);
            }
            else
            {
                // fallback: center of target
                arrowScript.Initialize(spawnPosition, hitPoint, target, damage);
            }

            Debug.Log($"Arrow will hit {target.CharacterName} at {hitPoint} for {damage} damage!");
        }
        else
        {
            // Arrow will miss - calculate miss position
            Vector3 missPosition = CalculateMissPosition(target.transform.position);
            Debug.Log($"Arrow will miss! Calculated miss position: {missPosition}");
            // Arrow will miss - call InitializeMiss directly
            arrowScript.InitializeMiss(spawnPosition, missPosition);
        }
    }

    private Vector3 CalculateMissPosition(Vector3 targetPosition)
    {
        // Calculate a random miss position around the target
        float missDistance = Random.Range(1f, 3f);
        float missAngle = Random.Range(0f, 360f) * Mathf.Deg2Rad;

        Vector3 missOffset = new Vector3(
            Mathf.Cos(missAngle) * missDistance,
            0f,
            Mathf.Sin(missAngle) * missDistance
        );

        return targetPosition + missOffset;
    }
}
