
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;
    public float smoothDistance => _smoothDistance;
    
    [Export] 
    public float minPitch = -89;

    [Export] 
    public float maxPitch = 89;

    [Export]
    public float minDistance = 0.001f;

    [Export]
    public float maxDistance = 200f;

    [Export]
    public float zoomSmoothingCoefficient = 0.1f;
    Smoother smoother = new Smoother();

    public Vector3 moveDirection = Vector3.Zero;

    [Export]
    public MouseEditorCameraInputSettings keyboardMouseInputs;

    [Export]
    public MouseEditorCameraInputSettings controllerInputs;

    float _cachedDistance = -1;

    public void CacheDistance()
    {
      if ( _cachedDistance < 0 )
      {
        return;
      }

      _cachedDistance = distance;

      GlobalPosition = target;
      distance = minDistance;

      this.LogInfo( "Cached Distance", _cachedDistance );
    }

    public void RestoreDistance()
    {
      if ( _cachedDistance < 0 )
      {
        return;
      }

      this.LogInfo( "Restored Distance", _cachedDistance );

      target = GlobalPosition + GlobalBasis.Z * _cachedDistance;
      distance = _cachedDistance;

      

      _cachedDistance = -1;

    }

    /*
    [ExportGroup("Orbit")]

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

    [Export]
    public Sensor mouseMovementOrbitButton;

    [Export]
    public Sensor[] orbitModifierButtons = [];
    
    [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("Pan")]

    [Export]
    public float panSpeedX = 0.01f;

    [Export]
    public float panSpeedY = 0.01f;

    [Export]
    public Sensor mouseMovementPanButton;
    
    [Export]
    public Sensor[] panModifierButtons = new Sensor[ 0 ];

    [ExportGroup("Zoom")]

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

    [Export]
    public float maxDistance = 200f;


    [Export]
    public Sensor zoomInButton;

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

    [Export]
    public Sensor zoomOutButton;

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


    [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;

    */

    [Export]
    public float running = 0;

    public override void _Process( double delta )
    {


      keyboardMouseInputs?.Orbit( this );
      controllerInputs?.Orbit( this );
      
      keyboardMouseInputs?.Pan( this );
      controllerInputs?.Pan( this );
      
      keyboardMouseInputs?.Zoom( this );
      controllerInputs?.Zoom( this );

      moveDirection = Vector3.Zero;

      keyboardMouseInputs?.Move( this );
      controllerInputs?.Move( this );

      Apply( (float) delta );

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

      hasMotionDelta = false;   
    }

    bool hasMotionDelta = false;
    Vector2 _motionDelta = Vector2.Zero;
    public Vector2 motionDelta => _motionDelta;

    public override void _Input( InputEvent inputEvent )
    {     
      var mouseMotionEvent = inputEvent as InputEventMouseMotion;

      if ( mouseMotionEvent == null )
      {
        return;
      }

      _motionDelta = mouseMotionEvent.ScreenRelative;
      hasMotionDelta = true;      
      
    }

    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;
      target -= moveDirection * delta;
      GlobalPosition = target + forward;
    }

    /*
    void OrbitByMouse()
    {
      if ( ! Sensors.IsActive( mouseMovementOrbitButton ) )
      {
        return;
      }

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

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

    void Orbit()
    {
      OrbitByMouse();
      yaw += Sensors.PolarAxis( yawDecreaseButton, yawIncreaseButton ) * yawButtonsSpeed;
      pitch += Sensors.PolarAxis( pitchDecreaseButton, pitchIncreaseButton ) * pitchButtonsSpeed;
    }

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

      var xAmount = _motionDelta.X * _smoothDistance * GlobalBasis.X * panSpeedX;
      var yAmount = _motionDelta.Y * _smoothDistance * GlobalBasis.Y * panSpeedY;

      target += xAmount + yAmount;
      
    }

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

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

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

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

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

    

    void Move()
    {
      moveDirection = Vector3.Zero;

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

      if ( Sensors.IsActive( upButton ) || Sensors.IsActive( downButton ) )
      {
        moveDirection = ( Sensors.GetValue( downButton ) - Sensors.GetValue( upButton ) ) * this.GlobalUp();
      }
      
      moveDirection = moveDirection.Normalized() * moveSpeed;
    }
    */

    
  }
}