// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest

#include <ocpp/v2/message_handler.hpp>

#pragma once

namespace ocpp::v2 {
struct FunctionalBlockContext;
class EvseInterface;

struct ReserveNowRequest;
struct CancelReservationRequest;

using ReserveNowCallback = std::function<ReserveNowStatusEnum(const ReserveNowRequest& request)>;
using CancelReservationCallback = std::function<bool(const std::int32_t reservationId)>;
using IsReservationForTokenCallback = std::function<ocpp::ReservationCheckStatus(
    const std::int32_t evse_id, const CiString<255> idToken, const std::optional<CiString<255>> groupIdToken)>;

class ReservationInterface : public MessageHandlerInterface {
public:
    ~ReservationInterface() override = default;
    virtual void on_reservation_status(const std::int32_t reservation_id, const ReservationUpdateStatusEnum status) = 0;
    virtual ocpp::ReservationCheckStatus
    is_evse_reserved_for_other(const EvseInterface& evse, const IdToken& id_token,
                               const std::optional<IdToken>& group_id_token) const = 0;
    virtual void on_reserved(const std::int32_t evse_id, const std::int32_t connector_id) = 0;
    virtual void on_reservation_cleared(const std::int32_t evse_id, const std::int32_t connector_id) = 0;
};

class Reservation : public ReservationInterface {
private: // Members
    const FunctionalBlockContext& context;

    /// \brief Callback function is called when a reservation request is received from the CSMS
    ReserveNowCallback reserve_now_callback;
    /// \brief Callback function is called when a cancel reservation request is received from the CSMS
    CancelReservationCallback cancel_reservation_callback;
    ///
    /// \brief Check if the current reservation for the given evse id is made for the id token / group id token.
    /// \return The reservation check status of this evse / id token.
    ///
    IsReservationForTokenCallback is_reservation_for_token_callback;

    // Functions
    void handle_reserve_now_request(Call<ReserveNowRequest> call);
    void handle_cancel_reservation_callback(Call<CancelReservationRequest> call);
    void send_reserve_now_rejected_response(const MessageId& unique_id, const std::string& status_info);

public:
    Reservation(const FunctionalBlockContext& functional_block_context, ReserveNowCallback reserve_now_callback,
                CancelReservationCallback cancel_reservation_callback,
                const IsReservationForTokenCallback is_reservation_for_token_callback);
    void handle_message(const ocpp::EnhancedMessage<MessageType>& message) override;

    void on_reservation_status(const std::int32_t reservation_id, const ReservationUpdateStatusEnum status) override;
    ocpp::ReservationCheckStatus
    is_evse_reserved_for_other(const EvseInterface& evse, const IdToken& id_token,
                               const std::optional<IdToken>& group_id_token) const override;
    void on_reserved(const std::int32_t evse_id, const std::int32_t connector_id) override;
    void on_reservation_cleared(const std::int32_t evse_id, const std::int32_t connector_id) override;
};

} // namespace ocpp::v2
