﻿using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections.Generic;

public class TouchOrbitCamera : MonoBehaviour
{
    [Header("Target")]
    public Transform target;

    [Header("Orbit")]
    public float distance = 5f;
    public float zoomSpeed = 1f;
    public float rotationSpeed = 5f;

    [Header("Limits")]
    public float minDistance = 2f;
    public float maxDistance = 20f;
    public float minYAngle = 10f;
    public float maxYAngle = 80f;

    [Header("Smoothing")]
    public float smoothTime = 0.1f;

    [Header("Pivot offset")]
    [Tooltip("Смещение точки вращения относительно таргета")]
    public Vector3 pivotOffset = new Vector3(0f, 1.5f, 0f);

    [Tooltip("Если включено — офсет задаётся в локальных координатах объекта")]
    public bool offsetInLocalSpace = true;

    [Header("UI блокировка")]
    [Tooltip("UI-слои, при наведении на которые камера НЕ должна крутиться (например, слой со слайдером)")]
    public LayerMask blockUiLayers;

    // внутреннее состояние
    float targetX, targetY, targetDistance;
    float currentX, currentY, currentDistance;
    float xVelocity, yVelocity, distanceVelocity;

    Vector3 focusPoint;      // текущая точка, вокруг которой крутимся
    Vector3 focusVelocity;

    Vector3 lastMousePosition;
    bool lastMousePositionValid = false;

    void Start()
    {
        if (target == null)
        {
            // если не задан таргет — создаём временный
            GameObject pivot = new GameObject("CameraTarget");
            pivot.transform.position = transform.position + transform.forward * distance;
            target = pivot.transform;
        }

        Vector3 angles = transform.eulerAngles;
        currentX = targetX = angles.y;
        currentY = targetY = angles.x;
        currentDistance = targetDistance = distance;

        focusPoint = GetPivotPosition();
    }

    /// <summary>
    /// Возвращает точку, вокруг которой должна вращаться камера,
    /// с учётом pivotOffset и выбора локальных/мировых координат.
    /// </summary>
    Vector3 GetPivotPosition()
    {
        if (target == null)
            return focusPoint;

        if (offsetInLocalSpace)
        {
            // офсет в локальных координатах объекта
            return target.TransformPoint(pivotOffset);
        }
        else
        {
            // офсет в мировых координатах
            return target.position + pivotOffset;
        }
    }

    /// <summary>
    /// Проверка: сейчас указатель/тач над UI-элементом из blockUiLayers?
    /// Остальной UI игнорируем.
    /// </summary>
    bool IsPointerOverBlockedUI()
    {
        if (EventSystem.current == null)
            return false;

        // МЫШЬ
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBGL
        if (Input.mousePresent)
        {
            PointerEventData data = new PointerEventData(EventSystem.current)
            {
                position = Input.mousePosition
            };
            List<RaycastResult> results = new List<RaycastResult>();
            EventSystem.current.RaycastAll(data, results);

            foreach (var r in results)
            {
                if (((1 << r.gameObject.layer) & blockUiLayers.value) != 0)
                    return true;
            }
        }
#endif

        // ТАЧ
        for (int i = 0; i < Input.touchCount; i++)
        {
            Touch t = Input.GetTouch(i);
            PointerEventData data = new PointerEventData(EventSystem.current)
            {
                position = t.position
            };
            List<RaycastResult> results = new List<RaycastResult>();
            EventSystem.current.RaycastAll(data, results);

            foreach (var r in results)
            {
                if (((1 << r.gameObject.layer) & blockUiLayers.value) != 0)
                    return true;
            }
        }

        return false;
    }

    void LateUpdate()
    {
        if (target == null)
            return;

        // если взаимодействуем с "блокирующим" UI — не крутим камеру и не зумим
        if (IsPointerOverBlockedUI())
        {
            lastMousePositionValid = false;

            // просто плавно держим камеру на месте вокруг pivot
            Vector3 desiredPivotUI = GetPivotPosition();
            focusPoint = Vector3.SmoothDamp(focusPoint, desiredPivotUI, ref focusVelocity, smoothTime);

            Quaternion rotationUI = Quaternion.Euler(currentY, currentX, 0f);
            Vector3 dirUI = new Vector3(0f, 0f, -currentDistance);
            transform.position = focusPoint + rotationUI * dirUI;
            transform.rotation = rotationUI;

            return;
        }

        // ===== МЫШЬ: вращение ЛКМ =====
        if (Input.GetMouseButton(0))
        {
            Vector3 currentPos = Input.mousePosition;

            if (!lastMousePositionValid)
            {
                lastMousePosition = currentPos;
                lastMousePositionValid = true;
            }

            Vector3 delta = currentPos - lastMousePosition;
            targetX += delta.x * rotationSpeed * 0.02f;
            targetY -= delta.y * rotationSpeed * 0.02f;

            lastMousePosition = currentPos;
        }
        else
        {
            lastMousePositionValid = false;
        }

        // ===== Зум колесом мыши =====
        float scroll = Input.GetAxis("Mouse ScrollWheel");
        if (Mathf.Abs(scroll) > 0.0001f)
        {
            targetDistance -= scroll * zoomSpeed * 5f;
            targetDistance = Mathf.Clamp(targetDistance, minDistance, maxDistance);
        }

        // ===== ТАЧ: один палец — орбита =====
        if (Input.touchCount == 1)
        {
            Touch t = Input.GetTouch(0);
            if (t.phase == TouchPhase.Moved)
            {
                Vector2 delta = t.deltaPosition;
                targetX -= delta.x * rotationSpeed * 0.1f;
                targetY += delta.y * rotationSpeed * 0.1f;
            }
        }
        // ===== ТАЧ: два пальца — пинч-зум =====
        else if (Input.touchCount == 2)
        {
            Touch t0 = Input.GetTouch(0);
            Touch t1 = Input.GetTouch(1);

            Vector2 prev0 = t0.position - t0.deltaPosition;
            Vector2 prev1 = t1.position - t1.deltaPosition;

            float prevDist = (prev0 - prev1).magnitude;
            float currDist = (t0.position - t1.position).magnitude;

            float delta = prevDist - currDist;
            targetDistance += delta * zoomSpeed * 0.01f;
            targetDistance = Mathf.Clamp(targetDistance, minDistance, maxDistance);
        }

        // Ограничения по высоте
        targetY = Mathf.Clamp(targetY, minYAngle, maxYAngle);

        // Плавные переходы
        currentX = Mathf.SmoothDampAngle(currentX, targetX, ref xVelocity, smoothTime);
        currentY = Mathf.SmoothDampAngle(currentY, targetY, ref yVelocity, smoothTime);
        currentDistance = Mathf.SmoothDamp(currentDistance, targetDistance, ref distanceVelocity, smoothTime);

        // Плавно тянем pivot к объекту с офсетом
        Vector3 desiredPivot = GetPivotPosition();
        focusPoint = Vector3.SmoothDamp(focusPoint, desiredPivot, ref focusVelocity, smoothTime);

        // Считаем позицию камеры вокруг focusPoint
        Quaternion rotation = Quaternion.Euler(currentY, currentX, 0f);
        Vector3 dir = new Vector3(0f, 0f, -currentDistance);

        transform.position = focusPoint + rotation * dir;
        transform.rotation = rotation;
    }

    /// <summary>
    /// Смена таргета в рантайме.
    /// keepCurrentPivot = true оставит старую точку фокуса,
    /// false — камера начнёт крутиться вокруг нового таргета с его офсетом.
    /// </summary>
    public void SetTarget(Transform newTarget, bool keepCurrentPivot = false)
    {
        target = newTarget;

        if (!keepCurrentPivot)
        {
            focusPoint = GetPivotPosition();
        }
    }
}
