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


namespace Rokojori
{  
  [Tool]
  [GlobalClass]
  public partial class EditorCameraInputSettings:Resource
  {

    [ExportGroup( "Orbit")]

        
    [Export]
    public float yawButtonsSpeed = 1;

    [Export]
    public Sensor yawDecreaseButton;

    [Export]
    public Sensor yawIncreaseButton;
    
    [Export]
    public float pitchButtonsSpeed = 1;

    [Export]
    public Sensor pitchDecreaseButton;

    [Export]
    public Sensor pitchIncreaseButton;


    [ExportGroup("Zoom")]

    [Export]
    public float zoomStepInPercentage = 10; 


    [Export]
    public Sensor zoomInButton;

    [Export]
    public Sensor[] zoomInModifierButtons = [];

    [Export]
    public Sensor zoomOutButton;

    [Export]
    public Sensor[] zoomOutModifierButtons = [];


    [Export]
    public Sensor continousZoomInButton;

    [Export]
    public Sensor continousZoomOutButton;

    [Export]
    public float continousZoomStepInPercentage = 1;


    [ExportGroup("Move")]
    [Export]
    public Sensor forwardButton;
    [Export]
    public Sensor backwardsButton;
    [Export]
    public Sensor leftButton;
    [Export]
    public Sensor rightButton;
    [Export]
    public Sensor upButton;
    [Export]
    public Sensor downButton;

    [Export]
    public float moveSpeed = 1;

    [ExportGroup( "Mouse Only")]

    [Export]
    public bool mouseMovementEnabled = false;

    [Export]
    public bool minimizeDistanceOnMovement = true;

    [ExportGroup( "Mouse Only/Orbit")]

    [Export]
    public float mouseMovementYawSpeed = 0.2f;
    
    [Export] 
    public float mouseMovementPitchSpeed = 0.2f;

    [Export]
    public Sensor mouseMovementOrbitButton;

    [Export]
    public Sensor[] mouseMovementOrbitModifierButtons = [];
        

    [ExportGroup( "Mouse Only/Pan")]

    [Export]
    public float mouseMovementPanSpeedX = 0.01f;

    [Export]
    public float mouseMovementPanSpeedY = 0.01f;
    
    [Export]
    public Sensor mouseMovementPanButton;
    
    [Export]
    public Sensor[] mouseMovementPanModifierButtons = [];


    public void Zoom( EditorCamera mouseEditorCamera )
    {
      if ( minimizeDistanceOnMovement )
      {
        mouseEditorCamera.RestoreDistance();
      }

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

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

      if ( Sensors.IsActive( continousZoomInButton ) )
      {
        mouseEditorCamera.distance *= Mathf.Pow( 1 + continousZoomStepInPercentage / 100f, 1 );
      }

      if ( Sensors.IsActive( continousZoomOutButton ) )
      {
        mouseEditorCamera.distance *= Mathf.Pow( 1 + continousZoomStepInPercentage / 100f, -1 );
      }

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

    
    public void Move( EditorCamera mouseEditorCamera )
    {
      Vector3 moveDirection = Vector3.Zero;

      var hasMovement = false;

      if ( Sensors.IsActive( forwardButton ) || Sensors.IsActive( backwardsButton ) )
      {
        hasMovement = true;
        moveDirection = ( Sensors.GetValue( forwardButton ) - Sensors.GetValue( backwardsButton ) ) * mouseEditorCamera.GlobalForward();
      }
      
      if ( Sensors.IsActive( rightButton ) || Sensors.IsActive( leftButton ) )
      {
        hasMovement = true;
        moveDirection = ( Sensors.GetValue( rightButton ) - Sensors.GetValue( leftButton ) ) * mouseEditorCamera.GlobalRight();
      }

      if ( Sensors.IsActive( upButton ) || Sensors.IsActive( downButton ) )
      {
        hasMovement = true;
        moveDirection = ( Sensors.GetValue( downButton ) - Sensors.GetValue( upButton ) ) * mouseEditorCamera.GlobalUp();
      }

      if ( ! hasMovement )
      {
        return;
      }

      if ( minimizeDistanceOnMovement )
      {
        mouseEditorCamera.CacheDistance();
      }
      
      mouseEditorCamera.moveDirection += moveDirection.Normalized() * moveSpeed;
    }

    void OrbitByMouse( EditorCamera mouseEditorCamera )
    {
      if ( ! mouseMovementEnabled )
      {
        return;
      }


      if ( ! Sensors.IsActive( mouseMovementOrbitButton ) )
      {
        return;
      }

      if ( minimizeDistanceOnMovement )
      {
        mouseEditorCamera.RestoreDistance();
      }

      mouseEditorCamera.yaw   += mouseEditorCamera.motionDelta.X * -mouseMovementYawSpeed; 
      mouseEditorCamera.pitch += mouseEditorCamera.motionDelta.Y * mouseMovementPitchSpeed;

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

    public void Orbit( EditorCamera mouseEditorCamera )
    {
      OrbitByMouse( mouseEditorCamera );

      mouseEditorCamera.yaw   += Sensors.PolarAxis( yawDecreaseButton, yawIncreaseButton ) * yawButtonsSpeed;
      mouseEditorCamera.pitch += Sensors.PolarAxis( pitchDecreaseButton, pitchIncreaseButton ) * pitchButtonsSpeed;
    }

    public void Pan( EditorCamera mouseEditorCamera )
    {
      if ( ! mouseMovementEnabled )
      {
        return;
      }


      if ( ! Sensors.IsActive( mouseMovementPanButton ) )
      {
        return;
      }

      if ( minimizeDistanceOnMovement )
      {
        mouseEditorCamera.RestoreDistance();
      }

      var xAmount = mouseEditorCamera.motionDelta.X * mouseEditorCamera.smoothDistance * 
                    mouseEditorCamera.GlobalBasis.X * mouseMovementPanSpeedX;

      var yAmount = mouseEditorCamera.motionDelta.Y * mouseEditorCamera.smoothDistance * 
                    mouseEditorCamera.GlobalBasis.Y * mouseMovementPanSpeedY;

      mouseEditorCamera.target += xAmount + yAmount;

      
    }
  }
}