using System;
using System.Collections.Generic;
using Creatures;
using Creatures.Player;
using Creatures.Player.Movement;
using UnityEngine;

public class Player : MonoBehaviour
{
    [Header("Setup")]
    [SerializeField]
    private InputManager _inputManager;
    [SerializeField]
    private GameObject _cameraGameObject;
    [SerializeField]
    private Animator _animator;
    
    [Header("Camera Options")]
    [SerializeField]
    private Vector3 camOffset;
    [SerializeField]
    private float cameraFollowSpeed = 2.5f;
    
    [Header("Player Options")]
    [Range(0f, 10f)]
    [SerializeField]
    private float moveSpeed = 6.5f;
    [Range(0f, 100f)]
    [SerializeField]
    private float animationSpeed = 10f;
    
    [Header("Enemy Snapping")]
    [SerializeField]
    private float minAimDistance;
    [SerializeField]
    private float maxAimDistance;
    [SerializeField]
    private Canvas aimCanvas;
    
    [Header("Dash")]
    [Range(0f, 100f)]
    public float dashSpeed = 7f;
    [Range(0f, 1f)]
    public float dashTime = 0.2f;
    [Range(0f, 4f)]
    public float dashCooldownTime = 1f;
    [SerializeField]
    public TrailRenderer dashTrail;

    [Header("Attacking")]
    [Range(0f, 10f)]
    [SerializeField]
    private float attackMoveSpeed = 2f;
    [Range(0f, 30f)]
    [SerializeField]
    private float _baseDamage;
    [SerializeField]
    [Range(0f, 0.1f)]
    private float _comboStep;
    [SerializeField]
    private AnimationCurve _comboCurve;
    [SerializeField]
    private LayerMask _enemyLayer;
    [SerializeField]
    private Collider _hurtBox;
    [SerializeField]
    private string[] _availableAttacks;
    
    [Header("Sound")]
    [SerializeField]
    private List<AudioClip> _hitSounds;
    [SerializeField]
    private List<AudioClip> _wooshSounds;
    [SerializeField]
    private List<AudioClip> _footStepSounds;
    [SerializeField]
    private float _footStepTime=0.3f;
    
    private Camera _camera;
    private CharacterController _controller;
    
    private Animate _animate;
    private PlayerMove _playerMove;
    private PlayerRotate _playerRotate;
    private PlayerAimRotate _playerAimRotate;
    private PlayerAttack _playerAttack;
    private CameraMove _cameraMove;
    private PlayerSound _playerSound;
    private PlayerVitalReaction _playerVitalReaction;
    
    void Awake()
    {
        SetupGame();
    }

    void SetupGame()
    {
        camOffset.z = camOffset.x;
        
        _camera = _cameraGameObject.GetComponent<Camera>();
        _controller = GetComponent<CharacterController>();
        _playerVitalReaction = gameObject.AddComponent<PlayerVitalReaction>();
        _playerRotate = gameObject.AddComponent<PlayerRotate>();
        
        
        _playerSound = gameObject.AddComponent<PlayerSound>();
        _playerSound.initalize(_hitSounds, _wooshSounds, _footStepSounds);
        _playerAimRotate = gameObject.AddComponent<PlayerAimRotate>();
        _playerAimRotate.initialize(aimCanvas);
        _animate = _animator.gameObject.AddComponent<Animate>();
        _animate.initialize(_animator);
        _playerAttack = gameObject.AddComponent<PlayerAttack>();
        _playerAttack.initialize(_inputManager, _enemyLayer, _animate, _hurtBox, _availableAttacks, _baseDamage, _comboStep, _comboCurve, _playerSound);
        _playerMove = gameObject.AddComponent<PlayerMove>();
        _playerMove.initialize(_controller, dashTrail, _playerSound, _footStepTime);
        _cameraMove = gameObject.AddComponent<CameraMove>();
        _cameraMove.initialize(transform, camOffset, cameraFollowSpeed, _camera.transform);
    }
    
    void Update()
    {
        Vector3 moveInput = new Vector3(_inputManager.moveInput.x, 0f , _inputManager.moveInput.y);

        bool attacking = _playerAttack.Attack();
        float movementSpeed = attacking ? attackMoveSpeed : moveSpeed;
        
        Vector3 aimTarget = _playerAimRotate.AimTarget(minAimDistance, maxAimDistance, _camera, _inputManager.aimInput);
        Vector3 moveDirection = _playerMove.GetMoveDirection(moveInput, _camera.transform);
        Vector3 lookTarget = attacking ? aimTarget : _playerRotate.LookTarget(moveDirection); // if player is attacking look towards attack direction.
        
        moveDirection += _playerMove.Gravity();
        _playerMove.Dash(dashTime, dashCooldownTime, dashSpeed, _inputManager.sprintPerformed, attacking);
        _playerMove.ApplyMovement(moveDirection, lookTarget, movementSpeed);
        _cameraMove.MoveCamera();
        _playerAimRotate.ApplyRotation(aimTarget);

        _animate.AnimateState("Walk", moveInput.magnitude, animationSpeed);
    }

}