using UnityEngine;

/// <summary>
/// CashBag — Collectible cash bag for Cash System mode.
/// Neutral gold color when spawned, takes team color on pickup.
/// Tracks state: Available → Carried → Dropped → Available/Destroyed.
/// Registers with EntityRegistry for zero-allocation queries.
/// Fires GameEvents instead of using FindObjectOfType.
/// The vault (TeamVault) is the "CashBox" where bags are deposited.
/// </summary>
public class CashBag : MonoBehaviour
{
    public enum BagState { Available, Carried, Dropped }

    [Header("Cash Settings")]
    [SerializeField] private float cashValue = 100f;
    [SerializeField] private float hotDropBonusPercent = 10f;   // +10% if picked during hot drop window

    [Header("Visual Feedback")]
    [SerializeField] private float rotationSpeed = 30f;
    [SerializeField] private float bobSpeed = 1f;
    [SerializeField] private float bobHeight = 0.2f;
    [SerializeField] private float floatOffset = 0.3f;
    [Header("Scale")]
    [SerializeField] private Vector3 targetScale = new Vector3(0.35f, 0.35f, 0.35f);

    [Header("Drop Settings")]
    [SerializeField] private float hotDropWindow = 3f;          // Seconds after drop where pickup gives bonus
    [SerializeField] private float dropDespawnTime = 30f;       // Despawn dropped bag after this time
    [SerializeField] private float pickupGracePeriod = 1.5f;    // Seconds after spawn/enable before pickup allowed

    [Header("Visual References")]
    [SerializeField] private MeshRenderer meshRenderer;
    [SerializeField] private ParticleSystem idleParticles;
    [SerializeField] private ParticleSystem pickupBurstEffect;
    [SerializeField] private ParticleSystem dropImpactEffect;
    [SerializeField] private GameObject glowObject;              // Point light or glow sprite
    [SerializeField] private GameObject worldIndicator;          // "!" icon for dropped bags

    [Header("Colors")]
    [SerializeField] private Color neutralColor = new Color(1f, 0.84f, 0f);         // Gold
    [SerializeField] private Color playerTeamColor = new Color(0.13f, 0.59f, 0.95f);// Blue
    [SerializeField] private Color enemyTeamColor = new Color(0.96f, 0.26f, 0.21f); // Red
    [SerializeField] private Color droppedPulseColor = new Color(1f, 0.84f, 0f);    // Pulsing gold

    [Header("Glow Settings")]
    [SerializeField] private float glowLightRange = 8f;
    [SerializeField] private float glowLightIntensity = 2f;
    [SerializeField] private Color glowLightColor = new Color(1f, 0.84f, 0f); // Gold
    [SerializeField] private float glowPulseSpeed = 2f;
    [SerializeField] private float glowPulseMin = 0.6f;
    [SerializeField] private float glowPulseMax = 1f;
    
    [Header("Audio")]
    [Tooltip("Sound effect played when this bag is picked up")]
    [SerializeField] private AudioClip pickupSound;
    [SerializeField] private float pickupSoundVolume = 3f;
    
    // ─── Runtime State ───────────────────────────────────────
    private BagState _state = BagState.Available;
    private CashCarrier _carrier;
    private Vector3 _spawnPosition;
    private float _dropTime;
    private float _despawnTimer;
    private Collider _collider;
    private Light _glowLight;
    private float _enabledTime; // Time.time when this bag was last enabled

    // Bob animation (randomized phase to desync multiple bags)
    private float _bobPhase;

    // ─── Properties ──────────────────────────────────────────
    public BagState State => _state;
    public float CashValue => cashValue;
    public float Value => cashValue;                // Alias for AI compatibility
    public bool IsAvailable => _state == BagState.Available;
    public bool IsDropped => _state == BagState.Dropped;
    public bool IsCarried => _state == BagState.Carried;
    public bool IsHotDrop => _state == BagState.Dropped && (Time.time - _dropTime) < hotDropWindow;
    public float HotDropBonusPercent => hotDropBonusPercent;
    public CashCarrier CurrentCarrier => _carrier;
    public Vector3 SpawnPosition => _spawnPosition;

    // ─── Lifecycle ───────────────────────────────────────────

    private void Awake()
    {
        if (meshRenderer == null) meshRenderer = GetComponent<MeshRenderer>();
        _collider = GetComponent<Collider>();

        if (_collider != null) _collider.isTrigger = true;
        _bobPhase = Random.Range(0f, Mathf.PI * 2f); // Desync bobs between bags
        
        // Create glow point light if none assigned
        CreateGlow();
    }

    private void OnEnable()
    {
        EntityRegistry<CashBag>.Register(this);
        _spawnPosition = transform.position;
        _enabledTime = Time.time;
        SetAvailable();
    }

    private void Reset()
    {
        // Ensure reasonable default scale when added in editor
        transform.localScale = targetScale;
    }

    private void OnDisable()
    {
        EntityRegistry<CashBag>.Unregister(this);
    }

    private void Update()
    {
        switch (_state)
        {
            case BagState.Available:
                AnimateIdle();
                break;

            case BagState.Carried:
                // Position managed by CashCarrier
                break;

            case BagState.Dropped:
                AnimateDropped();
                _despawnTimer += Time.deltaTime;
                if (_despawnTimer >= dropDespawnTime)
                    Despawn();
                break;
        }
    }

    // ─── State Transitions ───────────────────────────────────

    /// <summary>Reset to neutral available state.</summary>
    public void SetAvailable()
    {
        _state = BagState.Available;
        _carrier = null;
        _despawnTimer = 0f;

        if (_collider != null) _collider.enabled = true;
        if (meshRenderer != null) meshRenderer.enabled = true;
        gameObject.SetActive(true);

        // Ensure consistent visual scale
        transform.localScale = targetScale;

        SetColor(neutralColor);
        SetParticles(idleParticles, true);
        if (worldIndicator != null) worldIndicator.SetActive(false);
        
        // Enable glow so players can see the bag from far away
        SetGlowActive(true);

        // Show minimap marker when available
        var marker = GetComponent<MinimapObjectMarker>();
        if (marker != null) marker.SetVisible(true);
    }

    /// <summary>Picked up by a carrier.</summary>
    public void PickUp(CashCarrier carrier)
    {
        if (_state == BagState.Carried || carrier == null) return;

        _state = BagState.Carried;
        _carrier = carrier;

        // Disable world presence
        if (_collider != null) _collider.enabled = false;
        if (meshRenderer != null) meshRenderer.enabled = false;
        if (worldIndicator != null) worldIndicator.SetActive(false);
        SetParticles(idleParticles, false);

        // Burst pickup effect
        if (pickupBurstEffect != null)
        {
            pickupBurstEffect.transform.position = transform.position;
            pickupBurstEffect.Play();
        }
        
        // Play pickup sound effect (play at camera position so volume is consistent)
        if (pickupSound != null)
        {
            Vector3 listenerPos = Camera.main != null ? Camera.main.transform.position : transform.position;
            AudioSource.PlayClipAtPoint(pickupSound, listenerPos, pickupSoundVolume);
        }

        // Set team color
        Color teamColor = carrier.TeamTag == "Player" ? playerTeamColor : enemyTeamColor;
        SetColor(teamColor);
        
        // Hide glow while carried
        SetGlowActive(false);

        // Fire events (replaces FindObjectOfType calls)
        GameEvents.FireBagPickedUp(this, carrier);
        GameEvents.FireBagCollected(this);

        // Hide minimap marker while carried
        var marker = GetComponent<MinimapObjectMarker>();
        if (marker != null) marker.SetVisible(false);
    }

    /// <summary>Dropped at a world position (carrier died or lost it).</summary>
    public void Drop(Vector3 dropPosition)
    {
        _state = BagState.Dropped;
        _carrier = null;
        _dropTime = Time.time;
        _despawnTimer = 0f;

        // Re-enable world presence
        transform.position = dropPosition + Vector3.up * 0.5f;
        if (_collider != null) _collider.enabled = true;
        if (meshRenderer != null) meshRenderer.enabled = true;

        SetColor(droppedPulseColor);
        SetParticles(idleParticles, true);
        
        // Re-enable glow when dropped
        SetGlowActive(true);

        if (worldIndicator != null) worldIndicator.SetActive(true);

        // Impact effect
        if (dropImpactEffect != null)
        {
            dropImpactEffect.transform.position = dropPosition;
            dropImpactEffect.Play();
        }

        GameEvents.FireBagDropped(this, dropPosition);

        // Show minimap marker when dropped in world
        var marker = GetComponent<MinimapObjectMarker>();
        if (marker != null) marker.SetVisible(true);
    }

    /// <summary>Remove from play (despawn or deposited).</summary>
    public void Despawn()
    {
        _state = BagState.Available;
        _carrier = null;

        SetParticles(idleParticles, false);
        SetGlowActive(false);
        // Hide from world
        var marker = GetComponent<MinimapObjectMarker>();
        if (marker != null) marker.SetVisible(false);
        gameObject.SetActive(false);
        GameEvents.FireBagDespawned(this);

        // Return to pool if pooled, otherwise destroy
        var pooled = GetComponent<PooledObject>();
        if (pooled != null)
            pooled.ReturnToPool();
        else
            Destroy(gameObject, 0.1f);
    }

    // ─── Trigger Detection ───────────────────────────────────

    private void OnTriggerEnter(Collider other)
    {
        if (_state == BagState.Carried) return;

        if (SelectionOptions.Instance == null || !SelectionOptions.Instance.isCashSystemSelected) return;
        
        // Grace period: prevent insta-pickup when bag spawns on top of player
        if (Time.time - _enabledTime < pickupGracePeriod) return;

        // Use GetComponentInParent because collider may be on child (hand/foot)
        CashCarrier carrier = other.GetComponentInParent<CashCarrier>();
        if (carrier != null && carrier.CanPickUp())
        {
            PickUp(carrier);
            carrier.OnBagPickedUp(this);
        }
    }

    // ─── Glow ─────────────────────────────────────────────────

    private void CreateGlow()
    {
        // Use existing glowObject light if assigned in inspector
        if (glowObject != null)
        {
            _glowLight = glowObject.GetComponent<Light>();
            if (_glowLight != null) return;
        }
        
        // Create a point light child for long-range visibility
        GameObject lightObj = new GameObject("BagGlow");
        lightObj.transform.SetParent(transform, false);
        lightObj.transform.localPosition = Vector3.up * 0.3f;
        _glowLight = lightObj.AddComponent<Light>();
        _glowLight.type = LightType.Point;
        _glowLight.color = glowLightColor;
        _glowLight.range = glowLightRange;
        _glowLight.intensity = glowLightIntensity;
        _glowLight.shadows = LightShadows.None;
        _glowLight.renderMode = LightRenderMode.Auto;
        
        // Store as glowObject for other methods to reference
        if (glowObject == null)
            glowObject = lightObj;
    }
    
    private void SetGlowActive(bool active)
    {
        if (_glowLight != null) _glowLight.enabled = active;
        if (glowObject != null) glowObject.SetActive(active);
    }
    
    private void PulseGlow()
    {
        if (_glowLight == null) return;
        float pulse = Mathf.Lerp(glowPulseMin, glowPulseMax, (Mathf.Sin(Time.time * glowPulseSpeed + _bobPhase) + 1f) * 0.5f);
        _glowLight.intensity = glowLightIntensity * pulse;
    }

    // ─── Animations ──────────────────────────────────────────

    private void AnimateIdle()
    {
        // Rotate
        transform.Rotate(Vector3.up, rotationSpeed * Time.deltaTime, Space.World);

        // Bob
        float y = _spawnPosition.y + floatOffset + Mathf.Sin((Time.time + _bobPhase) * bobSpeed) * bobHeight;
        transform.position = new Vector3(transform.position.x, y, transform.position.z);
        
        // Pulse glow
        PulseGlow();
    }

    private void AnimateDropped()
    {
        // Faster pulse for hot drops
        float pulseSpeed = IsHotDrop ? bobSpeed * 2f : bobSpeed;
        float y = transform.position.y;
        float targetY = _spawnPosition.y + floatOffset + Mathf.Sin((Time.time + _bobPhase) * pulseSpeed) * bobHeight * 0.5f;

        // Smooth lerp for drop→bob transition
        transform.position = new Vector3(transform.position.x, Mathf.Lerp(y, targetY, Time.deltaTime * 3f), transform.position.z);

        // Pulse glow for hot drops
        if (IsHotDrop && glowObject != null)
        {
            float pulse = Mathf.PingPong(Time.time * 3f, 1f);
            glowObject.transform.localScale = Vector3.one * (1f + pulse * 0.3f);
        }
    }

    // ─── Visual Helpers ──────────────────────────────────────

    private void SetColor(Color color)
    {
        if (meshRenderer != null)
        {
            // MaterialPropertyBlock = zero allocation, no material instance created
            var mpb = new MaterialPropertyBlock();
            meshRenderer.GetPropertyBlock(mpb);
            mpb.SetColor("_BaseColor", color);
            mpb.SetColor("_EmissionColor", color * 1.2f); // Bright emission for visibility
            meshRenderer.SetPropertyBlock(mpb);
            
            // Enable emission keyword if possible
            if (meshRenderer.sharedMaterial != null)
                meshRenderer.sharedMaterial.EnableKeyword("_EMISSION");
        }

        if (glowObject != null)
        {
            Light light = glowObject.GetComponent<Light>();
            if (light != null) light.color = color;
        }
    }

    private void SetParticles(ParticleSystem ps, bool play)
    {
        if (ps == null) return;
        if (play && !ps.isPlaying) ps.Play();
        else if (!play && ps.isPlaying) ps.Stop(true, ParticleSystemStopBehavior.StopEmitting);
    }

    // ─── API ─────────────────────────────────────────────────

    /// <summary>Set the cash value (used by spawner).</summary>
    public void SetCashValue(float value) => cashValue = value;

    /// <summary>Get effective value including hot drop bonus.</summary>
    public float GetEffectiveValue()
    {
        if (IsHotDrop)
            return cashValue * (1f + hotDropBonusPercent / 100f);
        return cashValue;
    }

#if UNITY_EDITOR
    private void OnDrawGizmosSelected()
    {
        Gizmos.color = Color.yellow;
        Gizmos.DrawWireSphere(transform.position, 1.5f);
        UnityEditor.Handles.Label(transform.position + Vector3.up * 1.5f,
            $"CashBag ${cashValue}\n{_state}");
    }
#endif
}
