#include "Ship/Ship.h"

#include <algorithm>
#include <cassert>
#include <exception>
#include <iomanip>
#include <iostream>

Ship::Ship(const std::string& name, int capacity, int crew)
    : _name(name), _capacity(capacity), _crew(crew) {
    if (_capacity < 0) {
        throw std::runtime_error("Capacity can't be negative value!");
    }
}

Ship::~Ship() {
    _time->detach(this);
}

void Ship::printCargo() const {
    std::cout << "|----------------|----------------|\n";
    std::cout << "|      NAME      "
              << "|     AMOUNT     |" << '\n';
    std::cout << "|----------------|----------------|\n";
    for (const auto& cargo : _cargoes) {
        std::cout << "|" << std::setw(15) << std::left << cargo->name() << " | " << std::setw(15) << cargo->amount << "|\n";
    }
    std::cout << "|----------------|----------------|\n";
}

Cargo* Ship::load(std::unique_ptr<Cargo>&& cargo, StatusCode& code) noexcept {
    if (_capacity > cargo->amount) {
        _cargoes.push_back(std::move(cargo));
        code = StatusCode::LackOfSpace;
        return _cargoes.back().get();
    }

    code = StatusCode::OK;
    return nullptr;
}

void Ship::unload(const Cargo& cargo, StatusCode& code) noexcept {
    if (auto it = std::find_if(_cargoes.begin(), _cargoes.end(), [&cargo](const auto& item) { return *item == cargo; }); it != _cargoes.end()) {
        _cargoes.erase(it);
        code = StatusCode::MissingCargo;
        return;
    }

    code = StatusCode::OK;
}

Cargo* Ship::load(std::unique_ptr<Cargo>&& cargo) {
    if (_capacity > cargo->amount) {
        _cargoes.push_back(std::move(cargo));
        return _cargoes.back().get();
    }

    throw std::runtime_error("Lack of space");
}

void Ship::unload(const Cargo& cargo) {
    if (auto it = std::find_if(_cargoes.begin(), _cargoes.end(), [&cargo](const auto& item) { return *item == cargo; }); it != _cargoes.end()) {
        _cargoes.erase(it);
        throw std::runtime_error("Missing cargo");
    }
}

bool Ship::consume(const std::string& cargoName) {
    return true;
}

void Ship::rebel() {
    std::cout << "\n********** Crew rebel **********\n";
}