<?php

/**
 * 攻撃
 *
 */
class Attack extends Action
{
    private const DAMAGE_CORRECTION_MIN = 0;
    private const DAMAGE_CORRECTION_MAX = 5;
    private const CRITICAL_RATE_FAIL = 1;
    private const CRITICAL_RATE_SUCCESS = 2;
    private const BLOCK_RATE_FAIL = 1;
    private const BLOCK_RATE_SUCCESS = 0.5;

    /**
     * @inheritDoc
     */
    public function shouldBreak(): bool
    {
        if ($this->target->isDead()) {
            Logger::add("{$this->target->getName()}は死んでしまった。");
            return true;
        }

        return false;
    }

    /**
     * @inheritDoc
     */
    protected function action(): void
    {
        $damage = $this->calculateDamage();
        $this->target->subHp($damage);

        Logger::add($this->getDamageMessage($damage));
    }

    /**
     * ダメージ計算
     *
     * @return int
     */
    private function calculateDamage(): int
    {
        $damageCorrection = rand(self::DAMAGE_CORRECTION_MIN, self::DAMAGE_CORRECTION_MAX);
        $damageBase = $this->performer->getAtk() - $this->target->getDef() + $damageCorrection;
        $damageBase = max($damageBase, 0);

        $criticalRate = self::CRITICAL_RATE_FAIL;
        if ($damageBase > 0 && $this->performer->lotteryCriticalHit()) {
            $criticalRate = self::CRITICAL_RATE_SUCCESS;
        }

        $blockRate = self::BLOCK_RATE_FAIL;
        if ($damageBase > 0 && $this->target->lotteryBlockSuccess()) {
            $blockRate = self::BLOCK_RATE_SUCCESS;
        }

        return $damageBase * $criticalRate * $blockRate;
    }

    /**
     * ダメージメッセージを取得
     *
     * @param int $damage
     * @return string
     */
    private function getDamageMessage(int $damage): string
    {
        $message = '';
        if ($this->performer->isCriticalHit()) {
            $message .= "{$this->performer->getName()}の攻撃はクリティカルヒットした。";
        }

        if ($this->performer->isBlockSuccess()) {
            $message .= "{$this->target->getName()}は攻撃をブロックした。";
        }

        $message .= "{$this->performer->getName()}は{$this->target->getName()}に{$damage}のダメージ。 ";
        $message .= "{$this->target->getName()}のHP: {$this->target->getHp()}/{$this->target->getHpMax()} ({$this->target->getHpRate()}%)";

        return $message;
    }
}