using UnityEngine;
using UnityEngine.UI;
using TMPro;
using System.Collections;

/// <summary>
/// CashBoxImportController — Manages cash import to a TeamVault's CashBox.
/// Features:
/// - Spawns CashBox prefab at vault position with correct transform
/// - Countdown window based on import amount
/// - Reverse-plays "close" animation to open, then plays forward to close
/// - Camera focuses on player and cashbox during import
/// - Freezes player movement during import
/// - Sound effects for open/close/counting
/// 
/// Attach to the TeamVault or a manager object.
/// </summary>
public class CashBoxImportController : MonoBehaviour
{
    [Header("CashBox Prefab")]
    [Tooltip("CashBox prefab to spawn at the vault")]
    [SerializeField] private GameObject cashBoxPrefab;
    
    [Header("Spawn Transform (from prefab inspector)")]
    [SerializeField] private Vector3 spawnOffset = Vector3.zero;
    [SerializeField] private Vector3 spawnRotation = new Vector3(-90f, 0f, 0f);
    [SerializeField] private Vector3 spawnScale = new Vector3(60f, 60f, 60f);
    
    [Header("Animation Settings")]
    [Tooltip("Name of the close animation state")]
    [SerializeField] private string closeAnimationName = "close";
    [SerializeField] private float openAnimationDuration = 1f;
    [SerializeField] private float closeAnimationDuration = 1f;
    
    [Header("Import Settings")]
    [Tooltip("Seconds per $100 imported")]
    [SerializeField] private float countdownPerHundred = 0.5f;
    [SerializeField] private float minimumCountdown = 1f;
    [SerializeField] private float maximumCountdown = 10f;
    
    [Header("Camera Settings")]
    [SerializeField] private float cameraFocusDistance = 5f;
    [SerializeField] private float cameraFocusHeight = 2f;
    [SerializeField] private float cameraSmoothSpeed = 5f;
    
    [Header("Audio")]
    [Tooltip("Sound when CashBox opens")]
    [SerializeField] private AudioClip openSound;
    [Tooltip("Sound when CashBox closes")]
    [SerializeField] private AudioClip closeSound;
    [Tooltip("Looping sound during cash counting")]
    [SerializeField] private AudioClip countingSound;
    [Tooltip("Sound when import completes")]
    [SerializeField] private AudioClip completeSound;
    [SerializeField] private float soundVolume = 1f;
    
    [Header("UI References")]
    [SerializeField] private GameObject importUIPanel;
    [SerializeField] private TMP_Text countdownText;
    [Tooltip("Separate TMP for status label (e.g. 'IMPORTING'). Assign a TextMeshPro in your scene.")]
    [SerializeField] private TMP_Text statusText;
    [SerializeField] private TMP_Text amountText;
    [SerializeField] private Image progressDial;
    [Tooltip("Optional sprite for the circular dial (e.g. Thick_Dial)")]
    [SerializeField] private Sprite dialSprite;
    [Header("Scene References")]
    [Tooltip("Drag the TimeDial GameObject from the scene here (will use its Image component)")]
    [SerializeField] private GameObject progressDialObject;
    
    // Runtime
    private GameObject _spawnedCashBox;
    private Animator _cashBoxAnimator;
    private AudioSource _audioSource;
    private TeamVault _vault;
    private Camera _mainCamera;
    private Vector3 _originalCameraPosition;
    private Quaternion _originalCameraRotation;
    private Transform _originalCameraParent;
    private bool _isImporting;
    private CashCarrier _currentCarrier;
    
    public bool IsImporting => _isImporting;
    
    private void Awake()
    {
        _vault = GetComponent<TeamVault>();
        _audioSource = GetComponent<AudioSource>();
        if (_audioSource == null)
            _audioSource = gameObject.AddComponent<AudioSource>();
        
        _audioSource.playOnAwake = false;
        _audioSource.spatialBlend = 0f; // 2D sound for UI feedback
        
        _mainCamera = Camera.main;
        
        // If a GameObject was provided (e.g. your TimeDial), try to grab its Image component
        if (progressDial == null && progressDialObject != null)
        {
            var img = progressDialObject.GetComponent<Image>();
            if (img == null) img = progressDialObject.GetComponentInChildren<Image>();
            if (img != null)
            {
                progressDial = img;
                Debug.Log("[CashBoxImportController] Assigned progressDial from progressDialObject");
            }
            else
            {
                Debug.LogWarning("[CashBoxImportController] progressDialObject does not contain an Image component");
            }
        }
        
        // If a dial sprite was provided and progressDial exists, apply it
        if (progressDial != null && dialSprite != null)
        {
            progressDial.sprite = dialSprite;
            progressDial.type = Image.Type.Filled;
            progressDial.fillMethod = Image.FillMethod.Radial360;
            progressDial.fillOrigin = (int)Image.Origin360.Top;
            progressDial.fillClockwise = true;
            progressDial.fillAmount = 0f;
        }
    }
    
    private void Start()
    {
        // Auto-setup UI if not assigned
        if (importUIPanel == null)
            CreateImportUI();
        else
            importUIPanel.SetActive(false);
        
        // Auto-spawn CashBox on start if prefab is assigned
        if (cashBoxPrefab != null && _spawnedCashBox == null)
            SpawnCashBox();
    }
    
    /// <summary>
    /// Configure the controller from TeamVault at runtime (when added dynamically).
    /// </summary>
    public void Configure(GameObject prefab, Vector3 offset, Vector3 rotation, Vector3 scale)
    {
        cashBoxPrefab = prefab;
        spawnOffset = offset;
        spawnRotation = rotation;
        spawnScale = scale;
    }
    
    /// <summary>
    /// Spawn the CashBox at vault position. Call this on game start or when needed.
    /// </summary>
    public void SpawnCashBox()
    {
        if (cashBoxPrefab == null)
        {
            Debug.LogWarning("[CashBoxImportController] No CashBox prefab assigned!");
            return;
        }
        
        if (_spawnedCashBox != null)
        {
            Debug.Log("[CashBoxImportController] CashBox already spawned");
            return;
        }
        
        // Hide the vault's own visual mesh/renderers so only the CashBox is visible
        HideVaultVisuals();
        
        // Spawn at vault position with specified transform
        Vector3 spawnPos = transform.position + spawnOffset;
        Quaternion spawnRot = Quaternion.Euler(spawnRotation);
        
        _spawnedCashBox = Instantiate(cashBoxPrefab, spawnPos, spawnRot, transform);
        _spawnedCashBox.transform.localScale = spawnScale;
        _spawnedCashBox.name = "CashBox_" + (_vault != null ? _vault.TeamTag : "Vault");
        
        _cashBoxAnimator = _spawnedCashBox.GetComponent<Animator>();
        if (_cashBoxAnimator == null)
            _cashBoxAnimator = _spawnedCashBox.GetComponentInChildren<Animator>();
        
        Debug.Log($"[CashBoxImportController] Spawned CashBox at {spawnPos}, rotation {spawnRotation}, scale {spawnScale}");
    }
    
    /// <summary>
    /// Disable the vault's own mesh renderers so only the CashBox prefab shows.
    /// Skips any renderers on the spawned CashBox itself.
    /// </summary>
    private void HideVaultVisuals()
    {
        // Disable all renderers on the vault GameObject (not children that are the CashBox)
        foreach (var renderer in GetComponents<Renderer>())
        {
            renderer.enabled = false;
        }
        
        // Also disable renderers on existing vault children (the old "vault box")
        // but skip any previously spawned CashBox
        for (int i = 0; i < transform.childCount; i++)
        {
            Transform child = transform.GetChild(i);
            if (_spawnedCashBox != null && child.gameObject == _spawnedCashBox) continue;
            if (child.name.StartsWith("CashBox_")) continue; // Skip our CashBox
            
            foreach (var renderer in child.GetComponentsInChildren<Renderer>())
            {
                renderer.enabled = false;
                Debug.Log($"[CashBoxImportController] Disabled vault visual: {renderer.gameObject.name}");
            }
        }
    }
    
    /// <summary>
    /// Start the import process for a carrier depositing cash.
    /// </summary>
    public void StartImport(CashCarrier carrier)
    {
        if (_isImporting)
        {
            Debug.LogWarning("[CashBoxImportController] Import already in progress!");
            return;
        }
        
        if (carrier == null || carrier.CarriedCash <= 0)
        {
            Debug.LogWarning("[CashBoxImportController] No cash to import!");
            return;
        }
        
        // Spawn CashBox if not already
        if (_spawnedCashBox == null)
            SpawnCashBox();
        
        if (_spawnedCashBox == null)
        {
            Debug.LogError("[CashBoxImportController] Failed to spawn CashBox!");
            return;
        }
        
        _currentCarrier = carrier;
        StartCoroutine(ImportRoutine(carrier));
    }
    
    private IEnumerator ImportRoutine(CashCarrier carrier)
    {
        _isImporting = true;
        float cashAmount = carrier.CarriedCash;
        
        // Calculate countdown based on amount
        float countdownDuration = Mathf.Clamp(
            (cashAmount / 100f) * countdownPerHundred,
            minimumCountdown,
            maximumCountdown
        );
        
        Debug.Log($"[CashBoxImportController] Starting import of ${cashAmount:F0}, duration {countdownDuration:F1}s");
        
        // 1. Freeze player movement
        FreezeCarrier(carrier, true);
        
        // 2. Focus camera
        yield return StartCoroutine(FocusCamera(carrier.transform, _spawnedCashBox.transform));
        
        // 3. Show UI
        ShowImportUI(cashAmount, countdownDuration);
        
        // 4. Play open animation (reverse of close)
        yield return StartCoroutine(PlayAnimationReverse(closeAnimationName, openAnimationDuration));
        PlaySound(openSound);
        
        // 5. Countdown with cash counting sound
        yield return StartCoroutine(CountdownRoutine(cashAmount, countdownDuration));
        
        // 6. Play close animation (forward)
        yield return StartCoroutine(PlayAnimationForward(closeAnimationName, closeAnimationDuration));
        PlaySound(closeSound);
        
        // 7. Deposit the cash to vault
        if (_vault != null && carrier != null)
        {
            float deposited = carrier.DepositToVault(_vault);
            Debug.Log($"[CashBoxImportController] Deposited ${deposited:F0} to vault. Carrier now has ${carrier.CarriedCash:F0}");
        }
        else
        {
            Debug.LogError($"[CashBoxImportController] Deposit FAILED — vault: {_vault}, carrier: {carrier}");
        }
        
        // Force-clear any remaining carried cash display
        // DepositToVault clears bags, but fire event again as safety
        GameEvents.FireCashDeposited(
            carrier != null ? carrier.TeamTag : "Player",
            cashAmount, 1);
        
        PlaySound(completeSound);
        
        // 8. Hide UI
        HideImportUI();
        
        // 9. Restore camera
        yield return StartCoroutine(RestoreCamera());
        
        // 10. Unfreeze player
        FreezeCarrier(carrier, false);
        
        _isImporting = false;
        _currentCarrier = null;
        
        Debug.Log($"[CashBoxImportController] Import complete!");
    }
    
    /// <summary>
    /// Play animation in reverse by stepping normalizedTime from 1 to 0.
    /// </summary>
    private IEnumerator PlayAnimationReverse(string animName, float duration)
    {
        if (_cashBoxAnimator == null) yield break;
        
        float elapsed = 0f;
        
        // Start at end of animation (normalizedTime = 1)
        _cashBoxAnimator.Play(animName, 0, 1f);
        _cashBoxAnimator.speed = 0f; // Pause normal playback
        
        while (elapsed < duration)
        {
            elapsed += Time.deltaTime;
            float normalizedTime = 1f - (elapsed / duration); // Go from 1 to 0
            normalizedTime = Mathf.Clamp01(normalizedTime);
            
            // Continuously set the animation time
            _cashBoxAnimator.Play(animName, 0, normalizedTime);
            yield return null;
        }
        
        // Ensure we end at time 0 (fully open)
        _cashBoxAnimator.Play(animName, 0, 0f);
        _cashBoxAnimator.speed = 1f; // Restore normal speed
    }
    
    /// <summary>
    /// Play animation forward normally.
    /// </summary>
    private IEnumerator PlayAnimationForward(string animName, float duration)
    {
        if (_cashBoxAnimator == null) yield break;
        
        // Play from start
        _cashBoxAnimator.speed = 1f;
        _cashBoxAnimator.Play(animName, 0, 0f);
        
        yield return new WaitForSeconds(duration);
    }
    
    private IEnumerator FocusCamera(Transform playerTransform, Transform boxTransform)
    {
        if (_mainCamera == null) yield break;
        
        // Store original camera state
        _originalCameraPosition = _mainCamera.transform.position;
        _originalCameraRotation = _mainCamera.transform.rotation;
        _originalCameraParent = _mainCamera.transform.parent;
        
        // Detach camera temporarily
        _mainCamera.transform.SetParent(null);
        
        // Calculate target position (between player and box, offset back)
        Vector3 midPoint = (playerTransform.position + boxTransform.position) / 2f;
        Vector3 dirToBox = (boxTransform.position - playerTransform.position).normalized;
        Vector3 sideDir = Vector3.Cross(dirToBox, Vector3.up).normalized;
        
        Vector3 targetPos = midPoint + sideDir * cameraFocusDistance + Vector3.up * cameraFocusHeight;
        Quaternion targetRot = Quaternion.LookRotation(midPoint - targetPos);
        
        // Smooth move camera
        float elapsed = 0f;
        float focusDuration = 0.5f;
        
        while (elapsed < focusDuration)
        {
            elapsed += Time.deltaTime;
            float t = elapsed / focusDuration;
            t = t * t * (3f - 2f * t); // Smoothstep
            
            _mainCamera.transform.position = Vector3.Lerp(_originalCameraPosition, targetPos, t);
            _mainCamera.transform.rotation = Quaternion.Slerp(_originalCameraRotation, targetRot, t);
            yield return null;
        }
    }
    
    private IEnumerator RestoreCamera()
    {
        if (_mainCamera == null) yield break;
        
        Vector3 currentPos = _mainCamera.transform.position;
        Quaternion currentRot = _mainCamera.transform.rotation;
        
        float elapsed = 0f;
        float restoreDuration = 0.5f;
        
        while (elapsed < restoreDuration)
        {
            elapsed += Time.deltaTime;
            float t = elapsed / restoreDuration;
            t = t * t * (3f - 2f * t); // Smoothstep
            
            _mainCamera.transform.position = Vector3.Lerp(currentPos, _originalCameraPosition, t);
            _mainCamera.transform.rotation = Quaternion.Slerp(currentRot, _originalCameraRotation, t);
            yield return null;
        }
        
        // Re-parent camera
        if (_originalCameraParent != null)
            _mainCamera.transform.SetParent(_originalCameraParent);
    }
    
    private IEnumerator CountdownRoutine(float totalAmount, float duration)
    {
        float elapsed = 0f;
        
        // Start counting sound loop
        if (countingSound != null)
        {
            _audioSource.clip = countingSound;
            _audioSource.loop = true;
            _audioSource.volume = soundVolume * 0.7f;
            _audioSource.Play();
        }
        
        while (elapsed < duration)
        {
            elapsed += Time.deltaTime;
            float progress = elapsed / duration;
            float remaining = duration - elapsed;
            float countedAmount = totalAmount * progress;
            
            // Update UI
            UpdateImportUI(remaining, countedAmount, totalAmount, progress);
            
            yield return null;
        }
        
        // Stop counting sound
        if (_audioSource.isPlaying && _audioSource.clip == countingSound)
            _audioSource.Stop();
        
        // Final UI update
        UpdateImportUI(0f, totalAmount, totalAmount, 1f);
    }
    
    // Saved component states before freeze (restore exactly on unfreeze)
    private bool _carrierWasKinematic;
    private bool _aiWasEnabled;
    private bool _playerScriptWasEnabled;
    private bool _navAgentWasEnabled;
    private bool _navAgentWasStopped;
    private bool _cashAIWasEnabled;
    private bool _playerMovementWasEnabled;
    
    private void FreezeCarrier(CashCarrier carrier, bool freeze)
    {
        if (carrier == null) return;
        
        // CharacterAIController
        var aiController = carrier.GetComponent<CharacterAIController>();
        // PlayerScript
        var playerScript = carrier.GetComponent<PlayerScript>();
        // PlayerMovementBehaviour
        var playerMovement = carrier.GetComponent<PlayerMovementBehaviour>();
        // NavMeshAgent
        var navAgent = carrier.GetComponent<UnityEngine.AI.NavMeshAgent>();
        // CashSystemAI
        var cashAI = carrier.GetComponent<CashSystemAI>();
        // Rigidbody
        var rb = carrier.GetComponent<Rigidbody>();
        
        if (freeze)
        {
            // ─── SAVE original states BEFORE disabling ───
            _aiWasEnabled = aiController != null && aiController.enabled;
            _playerScriptWasEnabled = playerScript != null && playerScript.enabled;
            _playerMovementWasEnabled = playerMovement != null && playerMovement.enabled;
            _navAgentWasEnabled = navAgent != null && navAgent.enabled;
            _navAgentWasStopped = navAgent != null && navAgent.enabled && navAgent.isStopped;
            _cashAIWasEnabled = cashAI != null && cashAI.enabled;
            
            // Disable everything
            if (aiController != null) aiController.enabled = false;
            if (playerScript != null) playerScript.enabled = false;
            if (playerMovement != null) playerMovement.enabled = false;
            if (cashAI != null) cashAI.enabled = false;
            if (navAgent != null && navAgent.enabled) navAgent.isStopped = true;
            
            if (rb != null)
            {
                _carrierWasKinematic = rb.isKinematic;
                rb.isKinematic = true;
                rb.linearVelocity = Vector3.zero;
                rb.angularVelocity = Vector3.zero;
            }
        }
        else
        {
            // ─── RESTORE exactly the original states ───
            // Only re-enable components that were enabled BEFORE freeze
            if (aiController != null) aiController.enabled = _aiWasEnabled;
            if (playerScript != null) playerScript.enabled = _playerScriptWasEnabled;
            if (playerMovement != null) playerMovement.enabled = _playerMovementWasEnabled;
            if (cashAI != null) cashAI.enabled = _cashAIWasEnabled;
            
            if (navAgent != null)
            {
                // Only touch the agent if it was enabled before freeze
                if (_navAgentWasEnabled && navAgent.enabled)
                    navAgent.isStopped = _navAgentWasStopped;
            }
            
            if (rb != null)
            {
                rb.isKinematic = _carrierWasKinematic;
            }
        }
        
        Debug.Log($"[CashBoxImportController] Carrier movement {(freeze ? "frozen" : "restored")}");
    }

    
    private void PlaySound(AudioClip clip)
    {
        if (clip == null || _audioSource == null) return;
        _audioSource.PlayOneShot(clip, soundVolume);
    }
    
    // ─── UI Management ───────────────────────────────────────
    
    private void CreateImportUI()
    {
        // Create a simple runtime UI panel
        Canvas canvas = FindObjectOfType<Canvas>();
        if (canvas == null)
        {
            GameObject canvasObj = new GameObject("ImportUICanvas");
            canvas = canvasObj.AddComponent<Canvas>();
            canvas.renderMode = RenderMode.ScreenSpaceOverlay;
            canvasObj.AddComponent<CanvasScaler>();
            canvasObj.AddComponent<GraphicRaycaster>();
        }
        
        // Create panel
        importUIPanel = new GameObject("ImportUIPanel");
        importUIPanel.transform.SetParent(canvas.transform, false);
        
        RectTransform panelRect = importUIPanel.AddComponent<RectTransform>();
        panelRect.anchorMin = new Vector2(0.5f, 0.5f);
        panelRect.anchorMax = new Vector2(0.5f, 0.5f);
        panelRect.sizeDelta = new Vector2(400f, 150f);
        panelRect.anchoredPosition = new Vector2(0f, 100f);
        
        Image panelBg = importUIPanel.AddComponent<Image>();
        panelBg.color = new Color(0f, 0f, 0f, 0.8f);
        
        // Create countdown text
        GameObject countdownObj = new GameObject("CountdownText");
        countdownObj.transform.SetParent(importUIPanel.transform, false);
        RectTransform countdownRect = countdownObj.AddComponent<RectTransform>();
        countdownRect.anchorMin = new Vector2(0, 0.6f);
        countdownRect.anchorMax = new Vector2(1, 1f);
        countdownRect.offsetMin = Vector2.zero;
        countdownRect.offsetMax = Vector2.zero;
        
        countdownText = countdownObj.AddComponent<TextMeshProUGUI>();
        countdownText.text = "IMPORTING...";
        countdownText.fontSize = 36;
        countdownText.alignment = TextAlignmentOptions.Center;
        countdownText.color = Color.white;
        
        // Create amount text
        GameObject amountObj = new GameObject("AmountText");
        amountObj.transform.SetParent(importUIPanel.transform, false);
        RectTransform amountRect = amountObj.AddComponent<RectTransform>();
        amountRect.anchorMin = new Vector2(0, 0.3f);
        amountRect.anchorMax = new Vector2(1, 0.6f);
        amountRect.offsetMin = Vector2.zero;
        amountRect.offsetMax = Vector2.zero;
        
        amountText = amountObj.AddComponent<TextMeshProUGUI>();
        amountText.text = "$0";
        amountText.fontSize = 28;
        amountText.alignment = TextAlignmentOptions.Center;
        amountText.color = new Color(0.2f, 1f, 0.2f);
        
        // Create circular progress dial (radial Image)
        GameObject dialObj = new GameObject("ProgressDial");
        dialObj.transform.SetParent(importUIPanel.transform, false);
        RectTransform dialRect = dialObj.AddComponent<RectTransform>();
        dialRect.anchorMin = new Vector2(0.35f, 0.05f);
        dialRect.anchorMax = new Vector2(0.65f, 0.35f);
        dialRect.offsetMin = Vector2.zero;
        dialRect.offsetMax = Vector2.zero;

        progressDial = dialObj.AddComponent<Image>();
        if (dialSprite != null)
            progressDial.sprite = dialSprite;
        progressDial.type = Image.Type.Filled;
        progressDial.fillMethod = Image.FillMethod.Radial360;
        progressDial.fillOrigin = (int)Image.Origin360.Top;
        progressDial.fillClockwise = true;
        progressDial.fillAmount = 0f;
        progressDial.preserveAspect = true;
        
        importUIPanel.SetActive(false);
    }
    
    private void ShowImportUI(float totalAmount, float duration)
    {
        if (importUIPanel != null)
            importUIPanel.SetActive(true);
        
        UpdateImportUI(duration, 0f, totalAmount, 0f);
    }
    
    private void HideImportUI()
    {
        if (importUIPanel != null)
            importUIPanel.SetActive(false);
    }
    
    private void UpdateImportUI(float remaining, float counted, float total, float progress)
    {
        // Timer text: only the seconds number
        if (countdownText != null)
            countdownText.text = remaining > 0 ? $"{remaining:F1}" : "0";
        
        // Status text: label on a separate TMP
        if (statusText != null)
            statusText.text = remaining > 0 ? "IMPORTING" : "COMPLETE!";
        
        if (amountText != null)
            amountText.text = $"${counted:F0} / ${total:F0}";
        
        if (progressDial != null)
            progressDial.fillAmount = Mathf.Clamp01(progress);
    }
    
    // ─── Public API ──────────────────────────────────────────
    
    /// <summary>
    /// Check if a carrier can start importing (not already importing).
    /// </summary>
    public bool CanImport(CashCarrier carrier)
    {
        return !_isImporting && carrier != null && carrier.CarriedCash > 0;
    }
    
    /// <summary>
    /// Cancel current import (emergency use only).
    /// </summary>
    public void CancelImport()
    {
        if (!_isImporting) return;
        
        StopAllCoroutines();
        
        if (_currentCarrier != null)
            FreezeCarrier(_currentCarrier, false);
        
        HideImportUI();
        _isImporting = false;
        _currentCarrier = null;
        
        // Restore camera immediately
        if (_mainCamera != null && _originalCameraParent != null)
        {
            _mainCamera.transform.SetParent(_originalCameraParent);
            _mainCamera.transform.position = _originalCameraPosition;
            _mainCamera.transform.rotation = _originalCameraRotation;
        }
        
        Debug.Log("[CashBoxImportController] Import cancelled");
    }
}
