using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyCharacter : MonoBehaviour, IHittable, ICharacter {
    [SerializeField] Transform target;
    [SerializeField] Rigidbody body;
    [SerializeField] Animator animator;
    [SerializeField] float acc = 10.0f;
    [SerializeField] float maxSpeed = 2.0f;
    [SerializeField] float distanceToTarget = 1.0f;

    [SerializeField] Vector3 leftRotation = new Vector3(0.0f, 180.0f, 0.0f);
    [SerializeField] Vector3 rightRotation = new Vector3(0.0f, 0.0f, 0.0f);

    [SerializeField] Transform gfxTransf;

    [SerializeField] HitAnimator hitAnimator;

    [Header("Physics")]
    [SerializeField] Collider col;

    [Header("Sounds")]
    [SerializeField] GameSound hitSound;
    [SerializeField] GameSound deathSound;
    [SerializeField] GameSound detectSound;

    bool isDead = false;
    bool _isMoving = false;
    bool canAttack = false;

    [SerializeField] Equipment weaponPrefab;
    [SerializeField] Transform weaponHand;
    [SerializeField] Equipment weapon;

    EntityStats stats;
    [SerializeField] EntityStatsData statsData;

    [Header("Settings")]
    [SerializeField] Transform _transfGFX;
    [SerializeField] Transform _transfPhys;

    [Header("Effects")]
    [SerializeField] GameObject noticeEffect;
    [SerializeField] GameObject deathEffect;

    private void Awake() {
        stats = new EntityStats(statsData);   

        if(weaponPrefab != null) {
            weapon = Instantiate(weaponPrefab, weaponHand);
            weapon.ownerChar = this;
            weapon.ownerStats = stats;
            weapon.ownerCol = col;

            weapon.Init();
        }

        StartCoroutine(FollowTargetIE());
    }

    bool isMoving {
        get {
            return _isMoving;
        }

        set {
            if(_isMoving == value) return;

            _isMoving = value;
            animator.SetBool("IsMoving", _isMoving);
        }
    }

    public Transform transfPhys {
        get {
            return _transfPhys; 
        }
    }

    public Transform transfGFX {
        get {
            return _transfGFX; 
        }
    }

    public void Update() {
        stats.Update(Time.deltaTime);   
    }

    IEnumerator OnDetectTargetIE(Transform target) {
        Instantiate(noticeEffect, _transfGFX.position + Vector3.up * 1.5f, Quaternion.identity);

        yield return new WaitForSeconds(1.0f);
        this.target = target;
    }

    static Player playerBuf;
    public void OnTargetEnter(Collider col) {
        if(target != null) return;

        if(playerBuf = col.GetComponent<Player>()) {
            if(playerBuf != null) OnDetectTarget(playerBuf.transform);
        }
    }

    public void OnDetectTarget(Transform target) {
        if(detectSound != null) detectSound.Play();
        RotateToDirection(target.position - transfPhys.position);

        StartCoroutine(OnDetectTargetIE(target));
    }

    public void FixedUpdate() {
        UpdateAnimator();
    }

    float distBuf;
    float magBuf;
    float speedBuf;

    IEnumerator FollowTargetIE() {
        StartCoroutine(AttackIE());

        WaitForFixedUpdate wffu = new WaitForFixedUpdate();

        while(!isDead) {
            if(target == null) {
                yield return wffu;
                continue;
            }

            vecBuf = (target.position - body.position);
            vecBuf.z = vecBuf.z * 4.0f;
            distBuf = vecBuf.sqrMagnitude;
            if(distBuf > distanceToTarget) {
                canAttack = false;
                vecBuf.Normalize();

                body.velocity += vecBuf * acc * Time.fixedDeltaTime;

                speedBuf = (maxSpeed * maxSpeed);
                magBuf = body.velocity.sqrMagnitude;
                if(magBuf > speedBuf) {
                    body.velocity *= speedBuf / magBuf;
                }
            } else {
                canAttack = true;
                body.velocity *= 0.5f;
            }

            yield return wffu;
        }
    }

    static Vector3 vecBuf;

    IEnumerator AttackIE() {
        float timer = 0.0f;
        float attackTime = 1.0f;

        while(!isDead) {
            if(target == null) {
                yield return null;
                continue;
            }

            if(canAttack) {
                timer += Time.deltaTime;
                if(timer >= attackTime) {
                    timer -= attackTime;
                    Attack();
                }
            }
            else {
                timer = 0.0f;
            }

            yield return null;
        }
    }

    void UpdateAnimator() {
        vecBuf = body.velocity;
        isMoving = vecBuf.sqrMagnitude > 0.1f;

        RotateToDirection(vecBuf);
    }

    void RotateToDirection(Vector3 dir) {
        if(vecBuf.x < -0.01f) {
            gfxTransf.eulerAngles = leftRotation;
        } else if(vecBuf.x > 0.01f) {
            gfxTransf.eulerAngles = rightRotation;
        }
    }

    void Attack() {
        if(weapon != null) {
            weapon.Attack();
            animator.SetInteger("AttackMode", 0);
            animator.SetTrigger("Attack");
        }
    }

    public void Hit(float damage) {
        if(isDead) return;

        hitAnimator.PlayHit();
        hitSound.Play();

        stats.Hurt(damage);

        if(stats.isDead) {
            isDead = true;
            OnDeath();
        }
    }

    void OnDeath() {
        if(deathSound != null) deathSound.Play();

        animator.SetBool("IsDead", isDead);
        Instantiate(deathEffect, _transfGFX.position + Vector3.up * 1.5f, Quaternion.identity);
        col.enabled = false;
        body.isKinematic = true;

        if(weapon != null) Destroy(weapon.gameObject);

        SpawnLoot();
    }

    void SpawnLoot() {
        //TODO;
    }
}
