#pragma once

#include <memory>
#include <string>
#include <vector>

#include <Core/TimeObserver.h>
#include <Core/ShipStrategy.h>
#include "Ship/Cargo.h"

class Time;

template <typename T, typename Res>
class ShipEasyStrategy : public ShipStrategy<Res, T> {
    Res handle(T &t) override;
};

class Ship : public TimeObserver {
public:
    enum class StatusCode {
        OK,
        MissingCargo,
        LackOfSpace
    };

    Ship(Time* time, std::unique_ptr<ShipStrategy<Ship, bool>> strategy, const std::string& name, int capacity, int crew);
    ~Ship();
    Ship(const Ship&) = default;
    Ship(Ship&&) = default;
    Ship& operator=(const Ship&) = default;
    Ship& operator=(Ship&&) = default;

    // Override from TimeObserver
    void nextDay() override;

    std::string& name() { return _name; }
    const std::string& name() const { return _name; }
    int crew() const { return _crew; }

    void printCargo() const;

    Cargo* load(std::unique_ptr<Cargo>&& cargo, StatusCode& code) noexcept;
    void unload(const std::string& name, int amount, StatusCode& code) noexcept;

    // May throw
    Cargo* load(std::unique_ptr<Cargo>&& cargo);
    void unload(const std::string& name, int amount);

    void takeDamage(int damage);

private:
    bool consume(const std::string& cargoName);
    void rebel();

    Time* _time;
    std::string _name;
    ShipStrategy<Ship, bool> _strategy;
    int _capacity;
    int _crew;
    int _durability{1000};
    std::vector<std::unique_ptr<Cargo>> _cargoes;
};

