using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.VisualScripting;
using UnityEditor;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[SelectionBase]
public class Player : MonoBehaviour {
  [Header("Asset/Prefab")]
  [SerializeField] public BuilderManager Builder;

  [Header("Movement")]
  [SerializeField] private Rigidbody2D RigidBody;
  [SerializeField] public Animator Animator;
  [SerializeField] private SpriteRenderer Renderer;

  [Header("Character Class")]
  [SerializeField] private ParticleSystem Aura;
  [SerializeField] private GameObject[] ClassIndicators;
  private ClassBase ActiveClass;
  [SerializeField] private MeleeFighterClass FighterClass;
  public AttackAnimatorFactory AttackAnimator;


  [Header("Movement Attributes")]
  [SerializeField] public float MoveSpeed = 8;
  [SerializeField] private float DashMultiplier = 60;
  [SerializeField] private float DriftSpeed = 60;
  [SerializeField] private float DriftFactorial = 0.85f;

  [Header("VFX")]
  [SerializeField] private GameObject VfxDash;
  private VfxHandlerBase VfxDashHandler;



  public Vector2 PrevDirection = Vector2.zero;
  private Vector2 MoveDirection = Vector2.zero;
  private Directions FaceDir = Directions.Down;

  public bool IsJumping { get; private set; }
  public bool IsDashing { get; private set; }
  public float DashTime { get; private set; }
  public Vector2 DriftDirection { get; private set; } = Vector2.zero;
  private float Drift = 0;

  private readonly int AnimMoveRight = Animator.StringToHash("Anim_Player_MoveRight");
  private readonly int AnimIdleRight = Animator.StringToHash("Anim_Player_IdleRight");

  public bool SkillInUse = false;
  //{
  //  get { return Animator.GetBool("SkillActive"); }
  //  set { Animator.SetBool("SkillActive", value); }
  //}

  private enum Directions { Left, Right, Up, Down }

  void Awake() {
    Builder = GetComponent<BuilderManager>();

    VfxDashHandler = new VfxHandlerBase(VfxDash, 5, 5);
    FighterClass = new MeleeFighterClass(this);
    SetClass(1);
  }

  private void Update() {
    GatherInput();
    KeyPressActions();
    ActiveClass.Tick();
  }
  private void GatherInput() {
    MoveDirection.x = Input.GetAxisRaw("Horizontal");
    MoveDirection.y = Input.GetAxisRaw("Vertical");
  }

  private void KeyPressActions() {
    if (Input.GetKeyDown(KeyCode.LeftShift) || Input.GetKeyDown(KeyCode.RightShift)) {
      Dash(MoveDirection);
    } else if (Input.GetKeyDown(KeyCode.F1)) {
      SetClass(0);
    } else if (Input.GetKeyDown(KeyCode.F2)) {
      SetClass(1);
    } else if (Input.GetKeyDown(KeyCode.F3)) {
      SetClass(2);
    } else if (Input.GetKeyDown(KeyCode.F4)) {
      SetClass(3);
    }

    if (Input.GetMouseButtonDown(0)) ActiveClass.HandleLMB();
    else if (Input.GetMouseButtonDown(1)) ActiveClass.HandleRMB();
  }

  private void Dash(Vector2 direction) {
    if (SkillInUse) return;
    if (Drift > 0.5f) return;
    IsDashing = true;
    DashTime = Time.time;

    RigidBody.linearVelocity = direction.normalized * MoveSpeed * DashMultiplier;
    float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg + 180;
    if (direction.normalized != Vector2.zero)
      VfxDashHandler.PlayAll(this.transform.position, Quaternion.Euler(0f, 0f, angle));
    DriftDirection = direction.normalized;
    Drift = DriftSpeed;
    IsDashing = false;
  }

  private void SetClass(int classIdx) {
    Builder.SetBuildMode(classIdx == 3);
    ActiveClass = FighterClass;

    foreach (var (indicator, i) in ClassIndicators.Select((obj, i) => (obj, i)))
      if (i != classIdx) {
        indicator.transform.localScale = Vector3.one;
        indicator.transform.rotation = Quaternion.identity;
      } else {
        indicator.transform.localScale = Vector3.one * 2;
        indicator.transform.rotation = Quaternion.AngleAxis(90, Vector3.forward);
      }

    RawImage image = ClassIndicators[classIdx].GetComponent<RawImage>();
    var main = Aura.main;
    main.startColor = image.color;
  }



  private void FixedUpdate() {
    MovementUpdate();
    CalculateFacingDirection();
    UpdateAnimation();
  }

  private void MovementUpdate() {
    if (IsDashing) return;

    RigidBody.linearVelocity = MoveDirection.normalized * MoveSpeed;
    if (Drift > 0.2f) {
      RigidBody.linearVelocity += DriftDirection * Drift;
      Drift *= DriftFactorial;
    } else {
      Drift = 0f;
    }
  }


  private void CalculateFacingDirection() {
    if (MoveDirection.x != 0)
      if (MoveDirection.x < 0)
        FaceDir = Directions.Left;
      else
        FaceDir = Directions.Right;
  }

  private void UpdateAnimation() {
    string state = GetAnimationState(MoveDirection);
    Animator.CrossFade($"{state}{LastDirection.ToString()}", 0);
  }

  private enum Direction { Up, Down, Left, Right }
  private Direction LastDirection = Direction.Down;
  private string GetAnimationState(Vector2 input) {
    if (SkillInUse) return ActiveClass.AnimationToPlay;

    if (input.sqrMagnitude < 0.01f) {
      return "Idle";
      //return LastDirection switch {
      //  Direction.Up => "IdleUp",
      //  Direction.Down => "IdleDown",
      //  Direction.Left => "IdleLeft",
      //  Direction.Right => "IdleRight",
      //  _ => "IdleDown"
      //};
    }

    if (Mathf.Abs(input.x) > Mathf.Abs(input.y)) {
      LastDirection = (input.x > 0) ? Direction.Right : Direction.Left;
    } else {
      LastDirection = (input.y > 0) ? Direction.Up : Direction.Down;
    }

    return "Run";

    return LastDirection switch {
      Direction.Up => "RunUp",
      Direction.Down => "RunDown",
      Direction.Left => "RunLeft",
      Direction.Right => "RunRight",
      _ => "RunDown"
    };
  }



  void OnDrawGizmos() {
  }
}
