using System;
using KitsuneCafe.UI.MVVM;
using UnityEngine;
using UnityEngine.UIElements;

namespace KitsuneCafe.UI
{
  public class RotateEvent : EventBase<RotateEvent>
  {
    public Vector2 Delta { get; set; }

    protected override void Init()
    {
      base.Init();
      bubbles = true;
      tricklesDown = true;
    }
  }

  public class ZoomEvent : EventBase<ZoomEvent>
  {
    public float Amount { get; set; }

    protected override void Init()
    {
      base.Init();
      bubbles = true;
      tricklesDown = true;
    }
  }

  [UxmlElement]
  public partial class PreviewView : VisualElement
  {
    public const string BaseClass = "kitsunecafe__preview";

    private readonly PreviewViewModel viewModel = new();

    private readonly DragManipulator drag;

    public PreviewView()
    {
      AddToClassList(BaseClass);

      drag = new DragManipulator(this);
      drag.Started += () => viewModel.EnableRotationCommand.TryExecute(true);
      drag.Stopped += () => viewModel.EnableRotationCommand.TryExecute(false);
      drag.Dragged += delta => viewModel.RotateCommand.TryExecute(delta);
      this.AddManipulator(drag);

      RegisterCallback<AttachToPanelEvent>(OnAttachToPanel);
    }

    private void OnAttachToPanel(AttachToPanelEvent evt)
    {
      var root = panel.visualTree;
      root.RegisterCallback<WheelEvent>(OnMouseWheel);

      viewModel.Rotated += OnRotate;
      viewModel.Zoomed += OnZoom;
    }

    private void OnRotate(object sender, PreviewViewModel.RotateEvent e)
    {
      using RotateEvent ev = RotateEvent.GetPooled();
      ev.target = this;
      ev.Delta = e.Rotation;
      SendEvent(ev);
    }

    private void OnZoom(object sender, PreviewViewModel.ZoomEvent e)
    {
      using ZoomEvent ev = ZoomEvent.GetPooled();
      ev.target = this;
      ev.Amount = e.Amount;
      SendEvent(ev);
    }

    private void OnMouseWheel(WheelEvent evt)
    {
      viewModel.ZoomCommand.TryExecute(evt.delta.y);
    }
  }


  public class PreviewViewModel
  {
    public record RotateEvent(Vector2 Rotation);
    public record ZoomEvent(float Amount);

    public readonly ICommand<bool> EnableRotationCommand;
    public readonly ICommand<Vector2> RotateCommand;
    public readonly ICommand<float> ZoomCommand;

    private bool isRotating = false;

    public event EventHandler<RotateEvent> Rotated;
    public event EventHandler<ZoomEvent> Zoomed;

    public PreviewViewModel()
    {
      EnableRotationCommand = new RelayCommand<bool>(CanEnableRotation, EnableRotation);
      RotateCommand = new RelayCommand<Vector2>(CanRotate, Rotate);
      ZoomCommand = new RelayCommand<float>(CanZoom, Zoom);
    }

    private void EnableRotation(bool enabled)
    {
      isRotating = enabled;
    }

    private bool CanEnableRotation(bool _enabled)
    {
      return true;
    }

    public bool CanRotate(Vector2 _delta)
    {
      return isRotating;
    }

    private void Rotate(Vector2 delta)
    {
      Rotated?.Invoke(this, new RotateEvent(delta));
    }

    private bool CanZoom(float value)
    {
      return true;
    }

    private void Zoom(float value)
    {
      Zoomed?.Invoke(this, new ZoomEvent(value));
    }
  }
}

