using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System;
using Godot;


namespace Rokojori
{  
  [Tool]
  [GlobalClass]
  public partial class MouseEditorCamera:VirtualCamera3D
  {
    [Export]
    public Vector3 target;
    
    [Export]
    public float yaw = 0;

    [Export]
    public float pitch = 0; 

    [Export]
    public float distance = 10; 
    float smoothDistance = 10;

    [ExportCategory("Orbit")]

    [Export]
    public float yawSpeed = 1;
    
    [Export] 
    public float pitchSpeed = 1;

    [Export] 
    public float minPitch = -89;

    [Export] 
    public float maxPitch = 89;

    [Export]
    public RJSensor orbitButton;

    [Export]
    public RJSensor[] orbitModifierButtons;

    [ExportCategory("Pan")]

    [Export]
    public float panSpeedX = 1f;

    [Export]
    public float panSpeedY = 1f;

    [Export]
    public RJSensor panButton;
    
    [Export]
    public RJSensor[] panModifierButtons;

    [ExportCategory("Zoom")]

    [Export]
    public float zoomStepInPercentage = 10;
  
    [Export]
    public float minDistance = 0.001f;

    [Export]
    public float maxDistance = 200f;


    [Export]
    public RJSensor zoomInButton;

    [Export]
    public RJSensor[] zoomInModifierButtons;

    [Export]
    public RJSensor zoomOutButton;

    [Export]
    public RJSensor[] zoomOutModifierButtons;

    [Export]
    public float zoomSmoothingCoefficient = 0.1f;
    Smoother smoother = new Smoother();
    
    public override void _Process( double delta )
    {
      Orbit();
      Pan();      
      Zoom();

      Apply( (float) delta );

      if ( ! hasMotionDelta )
      {
        motionDelta.X = 0;
        motionDelta.Y = 0;
      }

      hasMotionDelta = false;   
    }

    bool hasMotionDelta = false;
    Vector2 motionDelta = Vector2.Zero;
    
    public override void _Input( InputEvent inputEvent )
    {     
      if ( inputEvent is InputEventMouseMotion )
      {
        var eventMouseMotion = inputEvent as InputEventMouseMotion;
        motionDelta = eventMouseMotion.ScreenRelative;
        hasMotionDelta = true;
      }
      
    }

    void Orbit()
    {
      if ( ! orbitButton.IsActive() )
      {
        return;
      }

      yaw += motionDelta.X * yawSpeed; 
      pitch += motionDelta.Y * pitchSpeed;

      pitch = Mathf.Clamp( pitch, minPitch, maxPitch );
      
    }

    void Pan()
    {
       if ( ! panButton.IsActive() )
      {
        return;
      }

      var xAmount = motionDelta.X * smoothDistance * GlobalBasis.X * panSpeedX;
      var yAmount = motionDelta.Y * smoothDistance * GlobalBasis.Y * panSpeedY;

      target += xAmount + yAmount;
      
    }

    void Zoom()
    {
      if ( zoomInButton.IsActive() )
      {
        distance *= Mathf.Pow( 1 + zoomStepInPercentage / 100f, 1 );
      }

      if ( zoomOutButton.IsActive() )
      {
        distance *= Mathf.Pow( 1 + zoomStepInPercentage / 100f, -1 );
      }

      distance = Mathf.Clamp( distance, minDistance, maxDistance );
    }


    void Apply( float delta )
    {
      smoothDistance = smoother.SmoothWithCoefficient( smoothDistance, distance, zoomSmoothingCoefficient, delta );
      GlobalRotation = new Vector3( Mathf.DegToRad( pitch ), Mathf.DegToRad( yaw ), 0 );

      var forward = Math3D.GetGlobalForward( this ) * smoothDistance;
      GlobalPosition = target + forward;
    }
  }
}