<?php

/**
 * バトルクラス
 */
class Battle
{
    public const TURN_DEFAULT = 1;
    private const TURN_LIMIT = 1000;

    /** @var BattleAble $player プレイヤー */
    private BattleAble $player;

    /** @var BattleAble $enemy 敵 */
    private BattleAble $enemy;

    /** @var int $turn ターン数 */
    private int $turn = self::TURN_DEFAULT;

    /**
     * constructor
     *
     * @param BattleAble $player
     * @param BattleAble $enemy
     */
    private function __construct(BattleAble $player, BattleAble $enemy)
    {
        $this->player = $player;
        $this->enemy = $enemy;
    }

    /**
     * バトル開始
     *
     * @param BattleAble $player
     * @param BattleAble $enemy
     * @return void
     */
    public static function start(BattleAble $player, BattleAble $enemy): void
    {
        (new self($player, $enemy))->run();
    }

    /**
     * バトル実行
     *
     * @return void
     */
    private function run(): void
    {
        Logger::add('バトル開始');
        Logger::add($this->player);
        Logger::add($this->enemy);
        Logger::add('');

        $participants = [$this->player, $this->enemy];
        while (!$this->isTurnLimit()) {

            Logger::add("{$this->turn}ターン目");

            // 感情に変化が起きたら感情を更新する
            foreach ($participants as $participant) {
                if ($participant instanceof HasEmotion) {
                    $emotionAnalyzer = new EmotionAnalyzer($this->turn, $participant, $this->getTarget($participant));
                    $emotion = $emotionAnalyzer->analyze();
                    if ($participant->getEmotion() !== $emotion) {
                        $participant->updateEmotion($emotion);
                        Logger::add("{$participant->getName()}は{$emotion->value}している。");
                    }
                }
            }

            // 行動
            foreach ($participants as $participant) {
                $action = $participant->action($this->getTarget($participant))->execute();
                if ($action->shouldBreak()) {
                    break 2;
                }
            }

            $this->turn++;

            Logger::add('');
        }

        Logger::add('バトル終了');
    }

    /**
     * ターン上限か
     *
     * @return bool true:上限, false:上限でない
     */
    private function isTurnLimit(): bool
    {
        return $this->turn >= self::TURN_LIMIT;
    }

    /**
     * ターゲットを取得
     *
     * @param BattleAble $performer 行動実行者
     * @return BattleAble
     */
    private function getTarget(BattleAble $performer): BattleAble
    {
        if ($this->player === $performer) {
            return $this->enemy;
        } else {
            return $this->player;
        }
    }
}