using UnityEngine;
using UnityEditor;
using gay.lilyy.PlaneCam;

namespace gay.lilyy.PlaneCam.Editor
{
    [InitializeOnLoad]
    public class PlaneCamEditor
    {
        static PlaneCamEditor()
        {
            EditorApplication.update += UpdatePlaneCams;
        }

        static void UpdatePlaneCams()
        {
            PlaneCam[] planeCams = Object.FindObjectsOfType<PlaneCam>(true);
            
            foreach (PlaneCam planeCam in planeCams)
            {
                if (planeCam == null || planeCam.target == null)
                    continue;

                Camera cam = planeCam.GetComponent<Camera>();
                if (cam == null)
                    continue;

                // Get the bounds of the target plane
                Bounds bounds = GetBounds(planeCam.target);
                
                if (bounds.size.magnitude < 0.001f)
                    continue;

                // Get plane normal and center
                Vector3 planeNormal = GetPlaneNormal(planeCam.target, planeCam.direction);
                Vector3 planeCenter = bounds.center;
                
                // Calculate the plane's dimensions in its local space
                // Project bounds size onto the plane's local axes
                Transform planeTransform = planeCam.target.transform;
                Vector3 localSize = bounds.size;
                
                // Find the two dimensions that define the plane (ignore the smallest dimension)
                // This assumes the plane is flat, so one dimension should be very small
                float minDim = Mathf.Min(localSize.x, localSize.y, localSize.z);
                float maxDim = Mathf.Max(localSize.x, localSize.y, localSize.z);
                float midDim = localSize.x + localSize.y + localSize.z - minDim - maxDim;
                
                // Use the larger of the two plane dimensions to ensure it fills the square viewport
                float planeSize = Mathf.Max(maxDim, midDim);

                // Set aspect ratio to 1:1 for square viewport
                cam.aspect = 1.0f;

                // Calculate distance and position
                if (cam.orthographic)
                {
                    cam.orthographicSize = planeSize * 0.5f;
                    // Position camera perpendicular to the plane
                    cam.transform.position = planeCenter - planeNormal * 10f; // Distance doesn't matter for orthographic
                    cam.transform.LookAt(planeCenter, planeTransform.up);
                }
                else
                {
                    // For perspective camera, calculate distance based on FOV
                    // distance = (size/2) / tan(FOV/2)
                    float halfFOV = cam.fieldOfView * 0.5f * Mathf.Deg2Rad;
                    float distance = (planeSize * 0.5f) / Mathf.Tan(halfFOV);
                    
                    // Position camera perpendicular to the plane, looking at center
                    cam.transform.position = planeCenter - planeNormal * distance;
                    cam.transform.LookAt(planeCenter, planeTransform.up);
                }
            }
        }

        static Bounds GetBounds(GameObject target)
        {
            Renderer renderer = target.GetComponent<Renderer>();
            if (renderer != null)
            {
                return renderer.bounds;
            }

            // If no renderer, try to get bounds from collider
            Collider collider = target.GetComponent<Collider>();
            if (collider != null)
            {
                return collider.bounds;
            }

            // Fallback: use transform scale
            return new Bounds(target.transform.position, target.transform.lossyScale);
        }

        static Vector3 GetPlaneNormal(GameObject target, PlaneDirection direction)
        {
            Transform t = target.transform;
            
            // Use the specified direction setting
            switch (direction)
            {
                case PlaneDirection.XPositive:
                    return t.right;
                case PlaneDirection.XNegative:
                    return -t.right;
                case PlaneDirection.YPositive:
                    return t.up;
                case PlaneDirection.YNegative:
                    return -t.up;
                case PlaneDirection.ZPositive:
                    return t.forward;
                case PlaneDirection.ZNegative:
                    return -t.forward;
                default:
                    return t.forward;
            }
        }
    }
}

