#pragma once

#include "Player/Player.h"

#include <Battle/Attack.h>
#include <Battle/BattleField.h>
#include <Battle/Defense.h>
#include <Core/DifficultLvlStrategy.h>
#include <Ship/Ship.h>

#include <memory>
#include <string>

template <typename DamageVisitor>
class Enemy : public Player {
public:
    Enemy(const std::string& name, std::unique_ptr<Ship>&& ship, std::unique_ptr<DifficultLvlStrategy<Ship, int>>&& strategy, DamageVisitor visitor);

    int attack(Ship& playerShip) override;
    Ship& getShip() { return *_ship; }
    const Ship& getShip() const { return *_ship; }

protected:
    Ship* chooseEnemyShip(const BattleField& battleField) const override final;
    std::unique_ptr<Action> chooseAction(const BattleField& battleField) const override final;

private:
    std::string _name;
    std::unique_ptr<Ship> _ship;
    std::unique_ptr<DifficultLvlStrategy<Ship, int>> _strategy;
    DamageVisitor _damageVisitor;
};

template <typename DamageVisitor>
Enemy<DamageVisitor>::Enemy(const std::string& name, std::unique_ptr<Ship>&& ship, std::unique_ptr<DifficultLvlStrategy<Ship, int>>&& strategy, DamageVisitor visitor)
    : _name(name), _ship(std::move(ship)), _strategy(std::move(strategy)), _damageVisitor(visitor) {}

template <typename DamageVisitor>
int Enemy<DamageVisitor>::attack(Ship& playerShip) {
    if (const auto damage = _strategy->handle(playerShip)) {
        for (auto& cargo : playerShip.cargoes()) {
            cargo->accept(_damageVisitor);
        }
        return damage;
    }

    return 0;
}

template <typename DamageVisitor>
Ship* Enemy<DamageVisitor>::chooseEnemyShip(const BattleField& battleField) const {
    // To simplify palyer and enemy has one ship
    return battleField.getPlayerShip();
}

template <typename DamageVisitor>
std::unique_ptr<Action> Enemy<DamageVisitor>::chooseAction(const BattleField& battleField) const {
    static bool flag = true;
    if (flag) {
        flag = !flag;
        return std::make_unique<Attack>();
    }

    flag = !flag;
    return std::make_unique<Defense>();
}
