<?php

/**
 * 敵クラス
 *
 */
class Enemy implements BattleAble, HasEmotion, Stringable
{
    private const EMOTION_DEFAULT = Emotion::COMMON;
    private const DEFENCE_RATE = 2;

    /** @var string $name 名前 */
    private string $name;

    /** @var int $hp HP */
    private int $hp;

    /** @var int $hpMax 最大HP */
    private int $hpMax;

    /** @var int $atk ATK */
    private int $atk;

    /** @var int $def DEF */
    private int $def;

    /** @var int $cri CRI */
    private int $cri;

    /** @var int $block BLOCK */
    private int $block;

    /** @var bool $isDefence 防御状態 */
    private bool $isDefence = false;

    /** @var bool クリティカルヒットしたか */
    private bool $isCriticalHit = false;

    /** @var bool ブロック成功したか */
    private bool $isBlockSuccess = false;

    /** @var Personality $personality 性格 */
    private Personality $personality;

    /** @var Emotion $emotion 感情 */
    private Emotion $emotion = self::EMOTION_DEFAULT;

    /** @var BehaviorPattern $behaviorPattern 行動パターン */
    private BehaviorPattern $behaviorPattern;

    /** @var StatusStrategy ステータスストラテジー */
    private StatusStrategy $statusStrategy;

    /**
     * constructor
     *
     * @param int $hpMax 最大HP
     * @param int $atk ATK
     * @param int $def DEF
     * @param int $cri CRI
     * @param int $block BLOCK
     * @param Personality $personality 性格
     */
    public function __construct(string $name, int $hpMax, int $atk, int $def, int $cri, int $block, Personality $personality)
    {
        $this->name = $name;
        $this->hp = $hpMax;
        $this->hpMax = $hpMax;
        $this->atk = $atk;
        $this->def = $def;
        $this->cri = $cri;
        $this->block = $block;
        $this->personality = $personality;
        $this->behaviorPattern = new BehaviorPattern($personality, $this->emotion);
        $this->setStatusStrategyFromEmotion($this->emotion);
    }

    /**
     * 文字列変換
     *
     * @return string
     */
    public function __toString(): string
    {
        return "名前:{$this->getName()} HP: {$this->getHp()}/{$this->getHpMax()} ({$this->getHpRate()}%) 性格: {$this->personality->value}";
    }

    /**
     * @inheritDoc
     */
    public function getName(): string
    {
        return $this->name;
    }

    /**
     * @inheritDoc
     */
    public function getHp(): int
    {
        return $this->statusStrategy->getHp($this->hp);
    }

    /**
     * @inheritDoc
     */
    public function subHp(int $value): void
    {
        $this->hp = max($this->hp - $value, self::HP_MIN);
    }

    /**
     * @inheritDoc
     */
    public function getHpMax(): int
    {
        return $this->statusStrategy->getHpMax($this->hpMax);
    }

    /**
     * @inheritDoc
     */
    public function getHpRate(): int
    {
        return $this->getHp() / $this->getHpMax() * BattleAble::PERCENTAGE;
    }

    /**
     * @inheritDoc
     */
    public function getAtk(): int
    {
        return $this->statusStrategy->getAtk($this->atk);
    }

    /**
     * @inheritDoc
     */
    public function getDef(): int
    {
        $def = $this->statusStrategy->getDef($this->def);

        return $this->isDefence ? $def * self::DEFENCE_RATE : $def;
    }

    /**
     * @inheritDoc
     */
    public function getCri(): int
    {
        return $this->statusStrategy->getCri($this->cri);
    }

    /**
     * @inheritDoc
     */
    public function getBlock(): int
    {
        return $this->statusStrategy->getBlock($this->block);
    }

    /**
     * @inheritDoc
     */
    public function getTotalStatus(): int
    {
        return $this->getHpMax() + $this->getAtk() + $this->getDef() + $this->getCri() + $this->getBlock();
    }

    /**
     * 感情を取得
     *
     * @return Emotion
     */
    public function getEmotion(): Emotion
    {
        return $this->emotion;
    }

    /**
     * 感情を更新
     *
     * @param Emotion $emotion
     * @return void
     */
    public function updateEmotion(Emotion $emotion): void
    {
        $this->emotion = $emotion;
        $this->behaviorPattern->setWeightStrategyFromEmotion($emotion);
        $this->setStatusStrategyFromEmotion($emotion);
    }

    /**
     * 性格を取得
     *
     * @return Personality
     */
    public function getPersonality(): Personality
    {
        return $this->personality;
    }

    /**
     * @inheritDoc
     */
    public function isDead(): bool
    {
        return $this->getHp() <= 0;
    }

    /**
     * @inheritDoc
     */
    public function action(BattleAble $target): Action
    {
        return match ($this->behaviorPattern->lotteryBehavior()) {
            Behavior::ATTACK => new Attack($this, $target),
            Behavior::DEFENCE => new Defence($this, $target),
            Behavior::WAIT => new Wait($this, $target),
            Behavior::ESCAPE => new Escape($this, $target),
        };
    }

    /**
     * @inheritDoc
     */
    public function setDefence(bool $isDefence): void
    {
        $this->isDefence = $isDefence;
    }

    /**
     * @inheritDoc
     */
    public function isDefence(): bool
    {
        return $this->isDefence;
    }

    /**
     * @inheritDoc
     */
    public function lotteryCriticalHit(): bool
    {
        $this->setCriticalHit(RandomUtil::lottery($this->getCri()));

        return $this->isCriticalHit();
    }

    /**
     * @inheritDoc
     */
    public function setCriticalHit(bool $isCriticalHit): void
    {
        $this->isCriticalHit = $isCriticalHit;
    }

    /**
     * @inheritDoc
     */
    public function isCriticalHit(): bool
    {
        return $this->isCriticalHit;
    }

    /**
     * @inheritDoc
     */
    public function lotteryBlockSuccess(): bool
    {
        $this->setBlockSuccess(RandomUtil::lottery($this->getBlock()));

        return $this->isBlockSuccess();
    }

    /**
     * @inheritDoc
     */
    public function setBlockSuccess(bool $isBlockSuccess): void
    {
        $this->isBlockSuccess = $isBlockSuccess;
    }

    /**
     * @inheritDoc
     */
    public function isBlockSuccess(): bool
    {
        return $this->isBlockSuccess;
    }

    /**
     * 感情からステータスストラテジーを設定
     *
     * @param Emotion $emotion
     * @return void
     */
    private function setStatusStrategyFromEmotion(Emotion $emotion): void
    {
        $this->statusStrategy = match ($emotion) {
            Emotion::COMMON => new CommonEmotionStatus(),
            Emotion::ARROGANCE => new ArroganceEmotionStatus(),
            Emotion::CAUTION => new CautionEmotionStatus(),
            Emotion::FEAR => new FearEmotionStatus(),
            Emotion::ANGER => new AngerEmotionStatus(),
        };
    }
}