#include "character/states/jobs/swordman/SwordmanBasicAttackHandler.h"
#include "character/CharacterObject.h"

namespace frostbite2D {
namespace {

constexpr float kAttackChainWindowBegin = 0.35f;
constexpr float kAttackChainWindowEnd = 0.95f;
constexpr float kDirectionalIntentThreshold = 0.25f;

struct AttackSlideConfig {
  float neutralDistance = 0.0f;
  float forwardDistance = 0.0f;
  float duration = 0.0f;
};

constexpr AttackSlideConfig kAttackSlideConfigs[] = {
    {0.0f, 0.0f, 0.0f},
    {10.0f, 15.0f, 0.15f},
    {10.0f, 15.0f, 0.15f},
    {10.0f, 15.0f, 0.15f},
};

} // namespace

SwordmanBasicAttackHandler::SwordmanBasicAttackHandler()
    : SwordmanActionHandlerBase("attack") {
}

void SwordmanBasicAttackHandler::OnEnter(CharacterStateContext& context,
                                         const CharacterActionDefinition& action) {
  (void)action;
  BeginComboStep(context, 1);
}

SwordmanActionUpdateResult SwordmanBasicAttackHandler::OnUpdate(
    CharacterStateContext& context,
    const CharacterActionDefinition& action) {
  (void)action;

  context.owner.GetMotorMutable().StopGroundMovement();
  if (comboStep_ == 1) {
    float progress = context.owner.GetCurrentAnimationProgressNormalized();
      if (progress >= kAttackChainWindowBegin
        && progress <= kAttackChainWindowEnd
        && context.commandBuffer.HasBufferedAction(GetActionId())) {
      context.commandBuffer.ConsumeAction(GetActionId());
      BeginComboStep(context, 2);
      return SwordmanActionUpdateResult::Running();
    }
  }

  if (comboStep_ == 2) {
    float progress = context.owner.GetCurrentAnimationProgressNormalized();
      if (progress >= kAttackChainWindowBegin
        && progress <= kAttackChainWindowEnd
        && context.commandBuffer.HasBufferedAction(GetActionId())) {
      context.commandBuffer.ConsumeAction(GetActionId());
      BeginComboStep(context, 3);
      return SwordmanActionUpdateResult::Running();
    }
  }

  return context.owner.IsCurrentAnimationFinished()
      ? SwordmanActionUpdateResult::Finished()
      : SwordmanActionUpdateResult::Running();
}

void SwordmanBasicAttackHandler::OnExit(CharacterStateContext& context,
                                        const CharacterActionDefinition& action) {
  (void)context;
  (void)action;
  comboStep_ = 0;
}

void SwordmanBasicAttackHandler::BeginComboStep(CharacterStateContext& context, int comboStep) {
  comboStep_ = comboStep;

  auto& owner = context.owner;
  auto& motor = owner.GetMotorMutable();
  motor.StopGroundMovement();

  switch (comboStep_) {
    case 1:
      owner.PlayAnimationTag("attack1");
      break;
    case 2:
      owner.PlayAnimationTag("attack2");
      break;
    case 3:
      owner.PlayAnimationTag("attack3");
      break;
    default:
      return;
  }

  const AttackSlideConfig& slideConfig = kAttackSlideConfigs[comboStep_];
  float forwardInputStrength = context.intent.moveX * static_cast<float>(motor.facing);
  float slideDistance = slideConfig.neutralDistance;
  if (forwardInputStrength >= kDirectionalIntentThreshold) {
    slideDistance = slideConfig.forwardDistance;
  } else if (forwardInputStrength <= -kDirectionalIntentThreshold) {
    slideDistance = 0.0f;
  }

  motor.StartForcedSlide(Vec2(static_cast<float>(motor.facing), 0.0f),
                         slideDistance, slideConfig.duration);
}

} // namespace frostbite2D
