using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Cinemachine;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.EventSystems;

public class CinemachineCameraController : MonoBehaviour
{
    public static CinemachineCameraController Instance { get; private set; }
    public CinemachineCamera actionCam;
    public GameObject groundPlane;

    [Header("Camera Controls")]
    public float minZoom = 15f;
    public float maxZoom = 200f;
    public float zoomSpeed = 10f;
    public float panSpeed = 30f;
    public float cameraAngle = 60f; // degrees
    private Vector3 framingPosition;
    private float framingHeight;
    private float framingDistance;
    private float zoomLevel;
    private Coroutine cameraMoveCoroutine;
    private Vector3 panOffset = Vector3.zero;
    private float yaw = 0f; // Add this field at the top with your other private fields


    private void Awake()
    {
        Instance = this;
    }

    private void Start()
    {
        FrameGroundPlane();
    }

    private void Update()
    {
        HandleCameraInput();
    }

    private void HandleCameraInput()
    {
        Rect gameArea = new Rect(0, 0, Screen.width, Screen.height);
        // Zoom
        if (Application.isFocused && !EventSystem.current.IsPointerOverGameObject() && gameArea.Contains(Input.mousePosition))
        {
            float scroll = Input.GetAxisRaw("Mouse ScrollWheel");
            if (Mathf.Abs(scroll) > 0.01f)
            {
                zoomLevel -= scroll * zoomSpeed;
                zoomLevel = Mathf.Clamp(zoomLevel, minZoom, maxZoom);
                FrameGroundPlane();
            }
        }


        // Pan (WASD or Arrow keys) - works even when paused
        Vector3 move = Vector3.zero;
        if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
            move.x -= 1f;
        if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
            move.x += 1f;
        if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
            move.z += 1f;
        if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
            move.z -= 1f;

        if (move != Vector3.zero)
        {
            panOffset += move.normalized * panSpeed * Time.unscaledDeltaTime;
            FrameGroundPlane();
        }

        // Rotate with middle mouse button
        if (Input.GetMouseButton(2))
        {
            float mouseX = Input.GetAxisRaw("Mouse X");
            yaw += mouseX * 3f;

            FrameGroundPlane();
        }

    }

    private void FrameGroundPlane()
    {
        if (groundPlane == null)
        {
            Debug.LogError("Ground plane is not assigned in CinemachineCameraController.");
            return;
        }

        // Use collider bounds to frame the ground plane
        Collider col = groundPlane.GetComponent<Collider>();
        if (col == null)
        {
            Debug.LogError("Ground plane does not have a collider to frame.");
            return;
        }

        Bounds bounds = col.bounds;
        Vector3 center = bounds.center + panOffset;
        float size = Mathf.Max(bounds.size.x, bounds.size.z);

        if (zoomLevel < 0.01f)
        {
            zoomLevel = size + 5f; // Ensure zoom level is not negative
        }

        float angleRadians = cameraAngle * Mathf.Deg2Rad;
        float y = Mathf.Sin(angleRadians) * zoomLevel;
        float z = -Mathf.Cos(angleRadians) * zoomLevel;

        Quaternion rotation = Quaternion.Euler(0, yaw, 0); // Apply yaw rotation
        Vector3 offset = rotation * new Vector3(0, y, z);

        framingPosition = center + offset;
        actionCam.transform.position = framingPosition;
        actionCam.transform.LookAt(center);
        actionCam.Follow = null;
        actionCam.LookAt = null;

        framingHeight = y;
        framingDistance = Mathf.Abs(z);
    }

    public void FocusOnCharacter(Transform character)
    {
        actionCam.Follow = character;
        actionCam.LookAt = character;
    }

    public void FollowTargetingLine(Vector3 mouseWorldPosition)
    {
        Vector3 target = new Vector3(mouseWorldPosition.x, 0, mouseWorldPosition.z) + panOffset;
        float angleRadians = cameraAngle * Mathf.Deg2Rad;
        float y = Mathf.Sin(angleRadians) * zoomLevel;
        float z = -Mathf.Cos(angleRadians) * zoomLevel;
        Vector3 camPos = target + new Vector3(0, y, z);
        actionCam.transform.position = camPos;
        actionCam.transform.LookAt(target);
        actionCam.Follow = null;
        actionCam.LookAt = null;
    }

    public void FrameAllCharacters(List<GameObject> characters)
    {
        if (characters == null || characters.Count == 0) return;
        Bounds bounds = new Bounds(characters[0].transform.position, Vector3.zero);
        foreach (var go in characters)
            bounds.Encapsulate(go.transform.position);

        Vector3 center = bounds.center + panOffset;
        float size = Mathf.Max(bounds.size.x, bounds.size.z);

        // Keep current zoomLevel, but allow zoom out if needed to fit all
        float requiredZoom = size + 5f;
        if (zoomLevel < requiredZoom)
        {
            zoomLevel = requiredZoom;
        }

        float angleRadians = cameraAngle * Mathf.Deg2Rad;
        float y = Mathf.Sin(angleRadians) * zoomLevel;
        float z = -Mathf.Cos(angleRadians) * zoomLevel;
        Vector3 camPos = center + new Vector3(0, y, z);

        // Start smooth movement
        if (cameraMoveCoroutine != null)
            StopCoroutine(cameraMoveCoroutine);
        cameraMoveCoroutine = StartCoroutine(SmoothMoveCamera(camPos, center, 0.7f));
    }

    private IEnumerator SmoothMoveCamera(Vector3 targetPosition, Vector3 lookAtTarget, float duration)
    {
        Vector3 startPos = actionCam.transform.position;
        Quaternion startRot = actionCam.transform.rotation;
        Quaternion endRot = Quaternion.LookRotation(lookAtTarget - targetPosition, Vector3.up);

        float elapsed = 0f;
        while (elapsed < duration)
        {
            float t = elapsed / duration;
            actionCam.transform.position = Vector3.Lerp(startPos, targetPosition, t);
            actionCam.transform.rotation = Quaternion.Slerp(startRot, endRot, t);
            elapsed += Time.deltaTime;
            yield return null;
        }
        actionCam.transform.position = targetPosition;
        actionCam.transform.rotation = endRot;
        actionCam.Follow = null;
        actionCam.LookAt = null;
    }
}
