using System;
using KitsuneCafe.ItemSystem;
using KitsuneCafe.SOAP;
using KitsuneCafe.Sys;
using R3;
using UnityEngine;
using Wacs.Core.Instructions;

namespace KitsuneCafe.UI
{
  public class ItemPreview : MonoBehaviour
  {
    [SerializeField]
    private ItemValue selectedItem;

    [SerializeField]
    private new Transform camera;

    [Header("Rotation")]
    [SerializeField]
    private Vector2Value rotationDelta;

    [SerializeField]
    private float sensitivity = 20;

    [SerializeField]
    private float angleSnap = 10;

    [Header("Zoom")]
    [SerializeField]
    private FloatValue zoom;

    [SerializeField]
    private float zoomSensitivity = 0.5f;

    private Vector3 initialPosition;

    [SerializeField]
    private Layer previewLayer;

    private GameObject instance;

    private void Start()
    {
      if (selectedItem.Value != null)
      {
        ChangeItemPreview(selectedItem.Value);
      }

      var d = Disposable.CreateBuilder();

      selectedItem.AsObservable()
        .Subscribe(ChangeItemPreview)
        .AddTo(ref d);

      rotationDelta.AsObservable()
        .Where(_ => instance != null)
        .Subscribe(RotatePreview)
        .AddTo(ref d);

      zoom.AsObservable()
        .Where(_ => instance != null)
        .Subscribe(ZoomPreview)
        .AddTo(ref d);

      d.RegisterTo(destroyCancellationToken);
    }

    private void ZoomPreview(float amount)
    {
      if (instance == null) { return; }

      var position = initialPosition;
      position.z += amount * zoomSensitivity;
      instance.transform.position = position;
    }

    private void ChangeItemPreview(Item item)
    {
      if (instance != null)
      {
        Destroy(instance);
        instance = null;
      }

      if (item != null)
      {
        instance = item.CreatePreview();
        instance.layer = previewLayer;
        instance.transform.SetParent(transform);
        initialPosition = instance.transform.position;

        ResetPreviewValues();
      }
    }

    private void ResetPreviewValues()
    {
      zoom.Value = 0;
      rotationDelta.Value = Vector2.zero;
    }

    public void RotatePreview(Vector2 delta)
    {
      if (instance == null || camera == null) { return; }

      var yawAngle = -delta.x * sensitivity * Time.deltaTime;
      var yawRotation = Quaternion.AngleAxis(yawAngle, camera.up);
      var pitchAngle = -delta.y * sensitivity * Time.deltaTime;

      var pitchRotation = Quaternion.AngleAxis(pitchAngle, camera.right);
      var combinedRotation = pitchRotation * yawRotation;
      instance.transform.rotation = combinedRotation * instance.transform.rotation;

      ApplyAngleSnapping();
    }

    public void ApplyAngleSnapping()
    {
      if (instance == null) return;

      Vector3 euler = instance.transform.rotation.eulerAngles;

      Quaternion rotation = Quaternion.Euler(
          Mathf.Round(euler.x / angleSnap) * angleSnap,
          Mathf.Round(euler.y / angleSnap) * angleSnap,
          Mathf.Round(euler.z / angleSnap) * angleSnap
      );

      instance.transform.rotation = rotation;
    }
  }
}
