using UnityEngine;
using Cinemachine;
using System.Collections;
using Unity.BossRoom.CameraUtils;

public class EdgePanningController : MonoBehaviour
{
    public CinemachineFreeLook virtualCamera;
    private CinemachineCameraOffset cameraOffset;

    private Coroutine shakeCoroutine;

    public float edgeThreshold = 50f; // Edge detection distance from screen edges
    public float resetRadiusPercentage = 3f; // Center reset radius in percentage of screen
    public float panSpeed = 0.1f; // How much to offset per frame
    public float resetSpeed = 2f; // Speed of resetting panning
    public Vector2 panLimit = new Vector2(0.5f, 0.5f); // Max panning limit (x, y)

    private Vector3 defaultOffset;
    private Vector3 panningOffset;
    private bool isPanning = false;
    private bool targetFound = false;
    private bool shouldReset = false; // Flag to trigger reset immediately

    private Transform targetCharacter; // The character the camera follows

    private void Start()
    {
        cameraOffset = virtualCamera.GetComponent<CinemachineCameraOffset>();
        if (cameraOffset == null)
        {
            Debug.LogError("[EdgePanningController] No CinemachineCameraOffset component found! Add it to the FreeLook Camera.");
            return;
        }

        defaultOffset = cameraOffset.m_Offset;
        panningOffset = defaultOffset;
    }

    private void Awake()
    {
        CameraController.OnCameraAttached += SetTargetCharacter;
    }

    private void OnDestroy()
    {
        CameraController.OnCameraAttached -= SetTargetCharacter;
    }

    private void SetTargetCharacter(Transform characterTransform)
    {
        targetCharacter = characterTransform.parent;
        targetFound = true;
    }

    private void Update()
    {
        if (targetFound)
            HandleEdgePanning();
    }

    private void HandleEdgePanning()
    {
        if (targetCharacter == null) return;

        Vector3 newOffset = panningOffset;
        Vector3 mousePos = Input.mousePosition;

        float screenWidth = Screen.width;
        float screenHeight = Screen.height;

        // Center Reset Radius (3% of screen size)
        float resetRadiusX = screenWidth * (resetRadiusPercentage / 100f);
        float resetRadiusY = screenHeight * (resetRadiusPercentage / 100f);
        Vector2 screenCenter = new Vector2(screenWidth / 2, screenHeight / 2);

        bool isNearCenter = Mathf.Abs(mousePos.x - screenCenter.x) <= resetRadiusX &&
                            Mathf.Abs(mousePos.y - screenCenter.y) <= resetRadiusY;

        bool isHoveringTarget = IsCursorOverTargetCharacter();

        // ✅ If the cursor touches the center or target **even for a millisecond**, trigger reset
        if (isNearCenter || isHoveringTarget)
        {
            shouldReset = true; // Set the flag so reset starts immediately
        }

        // ✅ If reset is triggered, smoothly return to default position
        if (shouldReset && isPanning)
        {
            cameraOffset.m_Offset = Vector3.Lerp(cameraOffset.m_Offset, defaultOffset, Time.deltaTime * resetSpeed);

            // ✅ Once back to default, stop resetting and reset flag
            if (Vector3.Distance(cameraOffset.m_Offset, defaultOffset) < 0.01f)
            {
                isPanning = false;
                panningOffset = defaultOffset;
                shouldReset = false; // Reset flag
            }
            return;
        }

        // If cursor is near the edges, start panning (up to limit)
        if (mousePos.x <= edgeThreshold) newOffset.x = Mathf.Max(defaultOffset.x - panLimit.x, newOffset.x - panSpeed);
        if (mousePos.x >= screenWidth - edgeThreshold) newOffset.x = Mathf.Min(defaultOffset.x + panLimit.x, newOffset.x + panSpeed);
        if (mousePos.y <= edgeThreshold) newOffset.y = Mathf.Max(defaultOffset.y - panLimit.y, newOffset.y - panSpeed);
        if (mousePos.y >= screenHeight - edgeThreshold) newOffset.y = Mathf.Min(defaultOffset.y + panLimit.y, newOffset.y + panSpeed);

        if (newOffset != panningOffset)
        {
            isPanning = true;
        }

        cameraOffset.m_Offset = Vector3.Lerp(cameraOffset.m_Offset, newOffset, Time.deltaTime * 3f);
        panningOffset = cameraOffset.m_Offset;
    }

    private bool IsCursorOverTargetCharacter()
    {
        if (targetCharacter == null) return false;

        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity))
        {
            return hit.transform == targetCharacter;
        }
        return false;
    }

    public void ShakeCamera(float duration = 0.3f, float magnitude = 0.2f)
    {
        if (shakeCoroutine != null)
        {
            StopCoroutine(shakeCoroutine);
        }
        shakeCoroutine = StartCoroutine(ShakeRoutine(duration, magnitude));
    }

    private IEnumerator ShakeRoutine(float duration, float magnitude)
    {
        float elapsed = 0f;
        Vector3 originalOffset = defaultOffset;

        while (elapsed < duration)
        {
            float x = Random.Range(-1f, 1f) * magnitude;
            float y = Random.Range(-1f, 1f) * magnitude;
            float z = Random.Range(-1f, 1f) * magnitude;

            cameraOffset.m_Offset = originalOffset + new Vector3(x, y, z);
            elapsed += Time.deltaTime;
            yield return null;
        }

        cameraOffset.m_Offset = originalOffset; // Reset to default offset
    }
}