#pragma once

#include <Core/DifficultLvlStrategy.h>

#include <Ship/Ship.h>

#include <algorithm>
#include <functional>
#include <iostream>
#include <memory>
#include <string>

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

    void attack(Ship& playerShip);

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>
void Enemy<DamageVisitor>::attack(Ship& playerShip) {
    std::cout << "Player: " << _name << " attack ship: " << playerShip.name() << '\n';
    if (const auto damage = _strategy->handle(playerShip)) {
        std::cout << "Dealed damage: " << damage << '\n';
        for (auto& cargo : playerShip.cargoes()) {
            cargo->accept(_damageVisitor);
        }
    } else {
        std::cout << "Missed\n";
    }
}
