#pragma once

#include "foundation/result.h"

#include <memory>
#include <string>
#include <string_view>

namespace pp::app {

enum class AppDialogKind {
    progress,
    message,
    input,
};

struct AppProgressDialogPlan {
    std::string title;
    int total = 0;
    int count = 0;
    float progress_fraction = 0.0F;
};

struct AppMessageDialogPlan {
    std::string title;
    std::string message;
    std::string ok_caption = "Ok";
    std::string cancel_caption = "Cancel";
    bool show_cancel = false;
};

struct AppInputDialogPlan {
    std::string title;
    std::string field_name;
    std::string ok_caption = "Ok";
};

class AppDialog {
public:
    virtual ~AppDialog() = default;
    [[nodiscard]] virtual AppDialogKind kind() const noexcept = 0;
};

class AppProgressDialog : public AppDialog {
public:
    ~AppProgressDialog() override = default;
};

class AppMessageDialog : public AppDialog {
public:
    ~AppMessageDialog() override = default;
};

class AppInputDialog : public AppDialog {
public:
    ~AppInputDialog() override = default;
};

class AppDialogFactory {
public:
    virtual ~AppDialogFactory() = default;

    [[nodiscard]] virtual std::shared_ptr<AppProgressDialog> show_progress_dialog(
        const AppProgressDialogPlan& plan) = 0;

    [[nodiscard]] virtual std::shared_ptr<AppMessageDialog> show_message_dialog(
        const AppMessageDialogPlan& plan) = 0;

    [[nodiscard]] virtual std::shared_ptr<AppInputDialog> show_input_dialog(
        const AppInputDialogPlan& plan) = 0;
};

[[nodiscard]] inline AppProgressDialogPlan plan_app_progress_dialog(
    std::string_view title,
    int total) noexcept
{
    return {
        std::string(title),
        total < 0 ? 0 : total,
        0,
        0.0F,
    };
}

[[nodiscard]] inline AppMessageDialogPlan plan_app_message_dialog(
    std::string_view title,
    std::string_view message,
    bool show_cancel,
    std::string_view ok_caption = "Ok",
    std::string_view cancel_caption = "Cancel")
{
    return {
        std::string(title),
        std::string(message),
        std::string(ok_caption),
        std::string(cancel_caption),
        show_cancel,
    };
}

[[nodiscard]] inline pp::foundation::Result<AppInputDialogPlan> plan_app_input_dialog(
    std::string_view title,
    std::string_view field_name,
    std::string_view ok_caption)
{
    if (ok_caption.empty()) {
        return pp::foundation::Result<AppInputDialogPlan>::failure(
            pp::foundation::Status::invalid_argument("input dialog ok caption must not be empty"));
    }

    return pp::foundation::Result<AppInputDialogPlan>::success({
        std::string(title),
        std::string(field_name),
        std::string(ok_caption),
    });
}

} // namespace pp::app
