using System;
using System.Collections.Generic;
using System.Linq;
using TagFighter.Effects;
using TagFighter.Martial;
using UnityEngine;

[Serializable]
public class MartialSequence : ISequence
{
    [UnityEngine.Serialization.FormerlySerializedAs("combatMoveRefs")]
    [SerializeField] List<CombatMoveRef> _combatMoveRefs;

    public MartialSequence(IEnumerable<CombatMoveRef> combatMoveRefsSequence) {
        _combatMoveRefs = combatMoveRefsSequence.ToList();
    }

    public bool Advance(ITimeContextContainer timeContextContainer, EffectContext effectContext, float deltaTime) {
        var timeContext = timeContextContainer.GetTimeContext<MartialSequence>();

        if (timeContext.CurrentIdx >= _combatMoveRefs.Count) {
            Debug.Log($"Executed Martial Sequence  {timeContext.CurrentIdx}/{_combatMoveRefs.Count} moves in {timeContext.CurrentTime} seconds");
            return false;
        }
        timeContext.CurrentTime += deltaTime;

        while ((timeContext.CurrentIdx < _combatMoveRefs.Count) && (timeContext.CurrentTime - timeContext.LastTime >= _combatMoveRefs[timeContext.CurrentIdx].CombatMove.Speed)) {
            Debug.Log($"Finished executing Martial move {_combatMoveRefs[timeContext.CurrentIdx].CombatMove.MoveName} {timeContext.CurrentIdx + 1}/{_combatMoveRefs.Count} at {timeContext.CurrentTime}");
            // TODO : Actual Execute Move
            timeContext.LastTime += _combatMoveRefs[timeContext.CurrentIdx].CombatMove.Speed;
            timeContext.CurrentIdx++;
        }
        SetReleaseMultiplier(timeContextContainer, effectContext);

        return true;
    }

    void SetReleaseMultiplier(ITimeContextContainer timeContextContainer, EffectContext context) {
        var currentMove = GetCurrentMove(timeContextContainer);
        if (currentMove == null) {
            return;
        }

        var caster = context.Caster;
        var animator = caster.Transform.gameObject.GetComponentInChildren<Animator>();
        var currentAnimationState = animator.GetCurrentAnimatorStateInfo(0);
        var posInAnimation = currentAnimationState.normalizedTime;

        //Debug.Log($"posInAnimation {posInAnimation}");


        var positionalReleaseMultiplier = 1f;
        if ((currentMove.StartReleaseNormalized < posInAnimation) && (posInAnimation < currentMove.EndReleaseNormalized)) {
            // this means we're in the maximal release section
            positionalReleaseMultiplier = 1f;
        }
        else if (posInAnimation < currentMove.StartReleaseNormalized) {
            // otherwise, get a partial bonus in reletaion to how close we are to the relese
            positionalReleaseMultiplier = posInAnimation / currentMove.StartReleaseNormalized;
        }
        else if (currentMove.EndReleaseNormalized < posInAnimation) {
            // otherwise, get a partial bonus in reletaion to how far we are from the release
            positionalReleaseMultiplier = (1 - posInAnimation) / (1 - currentMove.EndReleaseNormalized);
        }

        // Debug.Log($"positionalReleaseMultiplier {positionalReleaseMultiplier}");

        context.ReleaseMultiplier = new() {
            MatchingAoe = currentMove.MatchingAoe,
            MatchingAoeReleaseMultiplier = currentMove.MatchingAoeReleaseMultiplier * positionalReleaseMultiplier,
            NonMatchingAoeReleaseMultiplier = currentMove.NonMatchingAoeReleaseMultiplier * positionalReleaseMultiplier,
        };
    }

    public void Simulate() {

    }

    public CombatMove GetCurrentMove(ITimeContextContainer timeContextContainer) {
        if (timeContextContainer == null) {
            return null;
        }

        var timeContext = timeContextContainer.GetTimeContext<MartialSequence>();

        CombatMove move = default;
        if (timeContext.CurrentIdx < _combatMoveRefs.Count) {
            move = _combatMoveRefs[timeContext.CurrentIdx];
        }
        return move;
    }

    public IEnumerable<CombatMoveRef> GetSequence() => _combatMoveRefs;

    public float CompletionStatus(ITimeContextContainer timeContextContainer) {
        if (timeContextContainer == null) {
            return 0;
        }

        var timeContext = timeContextContainer.GetTimeContext<MartialSequence>();

        return timeContext.CurrentTime / _combatMoveRefs.Sum((move) => move.CombatMove.Speed);
    }
}