#include "wallet/lite_wallet_server_lifecycle_readiness.h"

#include <cctype>
#include <utility>

namespace dragonx::wallet {
namespace {

std::string trimCopy(const std::string& value)
{
    auto begin = value.begin();
    while (begin != value.end() && std::isspace(static_cast<unsigned char>(*begin))) ++begin;

    auto end = value.end();
    while (end != begin && std::isspace(static_cast<unsigned char>(*(end - 1)))) --end;

    return std::string(begin, end);
}

void addIssue(LiteWalletServerLifecycleReadinessResult& result,
              LiteWalletServerLifecycleReadinessIssue issue,
              std::string message)
{
    result.issues.push_back(LiteWalletServerLifecycleReadinessIssueInfo{issue, std::move(message)});
}

LiteWalletServerLifecycleReadinessResult stoppedResult(
    LiteWalletServerLifecycleReadinessResult result,
    LiteWalletServerLifecycleReadinessStatus status,
    LiteWalletServerLifecycleReadinessIssue issue,
    std::string message)
{
    result.status = status;
    addIssue(result, issue, std::move(message));
    result.error = result.issues.back().message;
    result.lifecycleStatus = WalletBackendStatus{WalletBackendState::Unavailable, result.error, {}, {}, 0.0};
    result.syncLifecycleInput.status = result.lifecycleStatus;
    return result;
}

LiteRedactedPrivateData redactedPrivateField(LitePrivateDataKind kind, const std::string& value)
{
    return LiteRedactedPrivateData{kind, !trimCopy(value).empty(), redactLitePrivateDataValue(value)};
}

bool privateDataIsRedacted(const std::vector<LiteRedactedPrivateData>& privateData)
{
    for (const auto& item : privateData) {
        if (!item.present && item.redactedValue != "<empty>") return false;
        if (item.present && item.redactedValue != "<redacted>") return false;
    }
    return true;
}

LiteWalletSelectedServerDisplayReport displayReportForSelection(
    const LiteServerSelectionResult& selection)
{
    LiteWalletSelectedServerDisplayReport report;
    if (!selection.ok) {
        report.status = LiteWalletSelectedServerDisplayStatus::Missing;
        report.message = selection.error.empty() ? "no usable lite server is selected" : selection.error;
        return report;
    }

    report.ok = true;
    report.status = selection.customServer
        ? LiteWalletSelectedServerDisplayStatus::CustomServer
        : LiteWalletSelectedServerDisplayStatus::SelectedServer;
    report.label = selection.server.label;
    report.url = selection.server.url;
    report.serverIndex = selection.serverIndex;
    report.customServer = selection.customServer;
    report.message = selection.customServer
        ? "custom lite server selected for display"
        : "configured lite server selected for display";
    return report;
}

LiteWalletLifecyclePlan lifecyclePlanForRequest(
    LiteWalletLifecycleOperation operation,
    const LiteServerSelectionResult& selection)
{
    LiteWalletLifecyclePlan plan;
    plan.operation = operation;
    plan.bridgeExecutionAllowed = false;
    if (!selection.ok) {
        plan.error = selection.error.empty() ? "no usable lite server is selected" : selection.error;
        return plan;
    }

    plan.ok = true;
    plan.server = selection.server;
    plan.serverIndex = selection.serverIndex;
    plan.customServer = selection.customServer;
    return plan;
}

LiteWalletLifecycleUiRequestPlan requestPlanForInput(
    const LiteWalletServerLifecycleReadinessInput& input,
    const LiteServerSelectionResult& selection)
{
    LiteWalletLifecycleUiRequestPlan plan;
    plan.operation = input.operation;
    plan.lifecyclePlan = lifecyclePlanForRequest(input.operation, selection);
    if (!plan.lifecyclePlan.ok) {
        plan.error = plan.lifecyclePlan.error;
        return plan;
    }

    switch (input.operation) {
        case LiteWalletLifecycleOperation::CreateNew:
            plan.privateData.push_back(redactedPrivateField(
                LitePrivateDataKind::Passphrase,
                input.createRequest.passphrase));
            plan.requestSummary = "operation=create;server=<selected>;passphrase=" +
                std::string(input.createRequest.passphrase.empty() ? "<empty>" : "<redacted>");
            break;
        case LiteWalletLifecycleOperation::OpenExisting:
            if (trimCopy(input.openRequest.walletPath).empty()) {
                plan.error = "lite wallet open requires a wallet path selected by the UI";
                return plan;
            }
            plan.privateData.push_back(redactedPrivateField(
                LitePrivateDataKind::WalletPath,
                input.openRequest.walletPath));
            plan.privateData.push_back(redactedPrivateField(
                LitePrivateDataKind::Passphrase,
                input.openRequest.passphrase));
            plan.requestSummary = "operation=open;server=<selected>;wallet_path=<redacted>;passphrase=" +
                std::string(input.openRequest.passphrase.empty() ? "<empty>" : "<redacted>");
            break;
        case LiteWalletLifecycleOperation::RestoreFromSeed:
            if (trimCopy(input.restoreRequest.seedPhrase).empty()) {
                plan.error = "lite wallet restore requires redacted seed material metadata";
                return plan;
            }
            plan.privateData.push_back(redactedPrivateField(
                LitePrivateDataKind::SeedPhrase,
                input.restoreRequest.seedPhrase));
            plan.privateData.push_back(redactedPrivateField(
                LitePrivateDataKind::WalletPath,
                input.restoreRequest.walletPath));
            plan.privateData.push_back(redactedPrivateField(
                LitePrivateDataKind::Passphrase,
                input.restoreRequest.passphrase));
            plan.requestSummary = "operation=restore;server=<selected>;seed=<redacted>;wallet_path=" +
                std::string(input.restoreRequest.walletPath.empty() ? "<empty>" : "<redacted>") +
                ";passphrase=" +
                std::string(input.restoreRequest.passphrase.empty() ? "<empty>" : "<redacted>");
            break;
    }

    plan.privateInputsRedacted = privateDataIsRedacted(plan.privateData);
    plan.lifecyclePlan.privateData = plan.privateData;
    plan.ok = plan.privateInputsRedacted;
    if (!plan.ok) plan.error = "lite wallet lifecycle private inputs are not redacted";
    return plan;
}

LiteWalletServerSelectionPersistencePlan persistencePlanForInput(
    const LiteWalletServerLifecycleReadinessInput& input,
    const LiteServerSelectionResult& selection)
{
    LiteWalletServerSelectionPersistencePlan plan;
    plan.settingsLoaded = input.persistence.settingsLoaded;
    plan.persistedSelectionIntentAccepted = input.persistence.havePersistedSelectionIntent;
    plan.wouldPersistSelectedServer = input.persistence.persistSelectedServer;
    plan.persistenceOwnerAccepted = input.persistence.persistenceOwnerReady;
    plan.selectionMode = input.settings.selectionMode;
    if (selection.ok) {
        plan.selectedServerUrl = selection.server.url;
        plan.selectedServerIndex = selection.serverIndex;
        plan.selectedServerCustom = selection.customServer;
    }
    plan.settingsWritten = false;
    plan.ok = true;
    return plan;
}

WalletBackendStatus readyLifecycleStatus(const LiteWalletSelectedServerDisplayReport& display)
{
    const std::string serverLabel = display.label.empty() ? display.url : display.label;
    return WalletBackendStatus{
        WalletBackendState::Disconnected,
        "lite lifecycle UI readiness accepted for " + serverLabel + "; wallet lifecycle execution is still disabled",
        {},
        {},
        0.0
    };
}

} // namespace

const char* liteWalletServerLifecycleReadinessStatusName(
    LiteWalletServerLifecycleReadinessStatus status)
{
    switch (status) {
        case LiteWalletServerLifecycleReadinessStatus::ReadyForFutureLifecycle: return "ReadyForFutureLifecycle";
        case LiteWalletServerLifecycleReadinessStatus::WaitingForLiteBuild: return "WaitingForLiteBuild";
        case LiteWalletServerLifecycleReadinessStatus::WaitingForBackendCapability: return "WaitingForBackendCapability";
        case LiteWalletServerLifecycleReadinessStatus::WaitingForServerSelection: return "WaitingForServerSelection";
        case LiteWalletServerLifecycleReadinessStatus::WaitingForPersistenceIntent: return "WaitingForPersistenceIntent";
        case LiteWalletServerLifecycleReadinessStatus::WaitingForDisplayStatus: return "WaitingForDisplayStatus";
        case LiteWalletServerLifecycleReadinessStatus::WaitingForLifecycleUi: return "WaitingForLifecycleUi";
        case LiteWalletServerLifecycleReadinessStatus::WaitingForPrivateDataRedaction: return "WaitingForPrivateDataRedaction";
        case LiteWalletServerLifecycleReadinessStatus::WaitingForSyncPlannerFeed: return "WaitingForSyncPlannerFeed";
        case LiteWalletServerLifecycleReadinessStatus::RuntimeExecutionDisabled: return "RuntimeExecutionDisabled";
    }
    return "Unknown";
}

const char* liteWalletServerLifecycleReadinessIssueName(
    LiteWalletServerLifecycleReadinessIssue issue)
{
    switch (issue) {
        case LiteWalletServerLifecycleReadinessIssue::FullNodeBuild: return "FullNodeBuild";
        case LiteWalletServerLifecycleReadinessIssue::LiteBackendCapabilityMissing: return "LiteBackendCapabilityMissing";
        case LiteWalletServerLifecycleReadinessIssue::PersistedSettingsNotLoaded: return "PersistedSettingsNotLoaded";
        case LiteWalletServerLifecycleReadinessIssue::PersistedServerSelectionIntentMissing: return "PersistedServerSelectionIntentMissing";
        case LiteWalletServerLifecycleReadinessIssue::ServerSelectionMissing: return "ServerSelectionMissing";
        case LiteWalletServerLifecycleReadinessIssue::ServerPersistenceOwnerMissing: return "ServerPersistenceOwnerMissing";
        case LiteWalletServerLifecycleReadinessIssue::SelectedServerDisplayMissing: return "SelectedServerDisplayMissing";
        case LiteWalletServerLifecycleReadinessIssue::LifecycleUiOwnerMissing: return "LifecycleUiOwnerMissing";
        case LiteWalletServerLifecycleReadinessIssue::LifecycleOperationUnconfirmed: return "LifecycleOperationUnconfirmed";
        case LiteWalletServerLifecycleReadinessIssue::OpenWalletPathMissing: return "OpenWalletPathMissing";
        case LiteWalletServerLifecycleReadinessIssue::RestoreSeedMissing: return "RestoreSeedMissing";
        case LiteWalletServerLifecycleReadinessIssue::PrivateDataRedactionMissing: return "PrivateDataRedactionMissing";
        case LiteWalletServerLifecycleReadinessIssue::SyncPlannerFeedMissing: return "SyncPlannerFeedMissing";
        case LiteWalletServerLifecycleReadinessIssue::RealLifecycleExecutionRequested: return "RealLifecycleExecutionRequested";
    }
    return "Unknown";
}

const char* liteWalletSelectedServerDisplayStatusName(
    LiteWalletSelectedServerDisplayStatus status)
{
    switch (status) {
        case LiteWalletSelectedServerDisplayStatus::Hidden: return "Hidden";
        case LiteWalletSelectedServerDisplayStatus::SelectedServer: return "SelectedServer";
        case LiteWalletSelectedServerDisplayStatus::CustomServer: return "CustomServer";
        case LiteWalletSelectedServerDisplayStatus::Missing: return "Missing";
    }
    return "Unknown";
}

LiteWalletServerLifecycleReadinessResult evaluateLiteWalletServerLifecycleReadiness(
    const LiteWalletServerLifecycleReadinessInput& input,
    LiteWalletServerLifecycleReadinessOptions options)
{
    LiteWalletServerLifecycleReadinessResult result;
    result.capabilities = input.capabilities;
    result.persistencePlan = persistencePlanForInput(input, {});

    if (options.requireLiteBuild && !isLiteBuild(input.capabilities)) {
        return stoppedResult(
            std::move(result),
            LiteWalletServerLifecycleReadinessStatus::WaitingForLiteBuild,
            LiteWalletServerLifecycleReadinessIssue::FullNodeBuild,
            "lite server lifecycle readiness requires a lite build");
    }
    result.liteBuildAccepted = true;

    if (options.requireLiteBackendCapability && !supportsLiteBackend(input.capabilities)) {
        return stoppedResult(
            std::move(result),
            LiteWalletServerLifecycleReadinessStatus::WaitingForBackendCapability,
            LiteWalletServerLifecycleReadinessIssue::LiteBackendCapabilityMissing,
            "lite backend capability is required before lifecycle UI readiness can feed sync planners");
    }
    result.backendCapabilityAccepted = true;

    if (options.requirePersistedSettingsLoaded && !input.persistence.settingsLoaded) {
        return stoppedResult(
            std::move(result),
            LiteWalletServerLifecycleReadinessStatus::WaitingForPersistenceIntent,
            LiteWalletServerLifecycleReadinessIssue::PersistedSettingsNotLoaded,
            "lite server settings must be loaded before lifecycle UI readiness is evaluated");
    }

    if (options.requirePersistedSelectionIntent && !input.persistence.havePersistedSelectionIntent) {
        return stoppedResult(
            std::move(result),
            LiteWalletServerLifecycleReadinessStatus::WaitingForPersistenceIntent,
            LiteWalletServerLifecycleReadinessIssue::PersistedServerSelectionIntentMissing,
            "lite server selection persistence intent is missing");
    }

    result.selectedServer = selectLiteServer(input.settings);
    result.persistencePlan = persistencePlanForInput(input, result.selectedServer);
    if (!result.selectedServer.ok) {
        return stoppedResult(
            std::move(result),
            LiteWalletServerLifecycleReadinessStatus::WaitingForServerSelection,
            LiteWalletServerLifecycleReadinessIssue::ServerSelectionMissing,
            result.selectedServer.error.empty()
                ? "no usable lite server is selected"
                : result.selectedServer.error);
    }
    result.serverSelectionAccepted = true;

    if (input.persistence.persistSelectedServer && !input.persistence.persistenceOwnerReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletServerLifecycleReadinessStatus::WaitingForPersistenceIntent,
            LiteWalletServerLifecycleReadinessIssue::ServerPersistenceOwnerMissing,
            "lite server selection persistence owner is not ready");
    }
    result.persistenceIntentAccepted = true;
    result.persistencePlan.ok = true;

    result.selectedServerDisplay = displayReportForSelection(result.selectedServer);
    if (options.requireSelectedServerDisplay && !input.ui.selectedServerDisplayReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletServerLifecycleReadinessStatus::WaitingForDisplayStatus,
            LiteWalletServerLifecycleReadinessIssue::SelectedServerDisplayMissing,
            "selected lite server display status is not ready");
    }
    result.selectedServerDisplayAccepted = true;

    if (options.requireLifecycleUiOwner && !input.ui.lifecycleUiOwnerReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletServerLifecycleReadinessStatus::WaitingForLifecycleUi,
            LiteWalletServerLifecycleReadinessIssue::LifecycleUiOwnerMissing,
            "lite wallet lifecycle UI owner is not ready");
    }
    result.lifecycleUiOwnerAccepted = true;

    if (input.ui.realLifecycleExecutionRequested) {
        return stoppedResult(
            std::move(result),
            LiteWalletServerLifecycleReadinessStatus::RuntimeExecutionDisabled,
            LiteWalletServerLifecycleReadinessIssue::RealLifecycleExecutionRequested,
            "real lite wallet lifecycle execution is disabled in this scaffold");
    }

    if (options.requireOperationConfirmation && !input.ui.operationConfirmed) {
        return stoppedResult(
            std::move(result),
            LiteWalletServerLifecycleReadinessStatus::WaitingForLifecycleUi,
            LiteWalletServerLifecycleReadinessIssue::LifecycleOperationUnconfirmed,
            "lite wallet lifecycle operation requires explicit UI confirmation");
    }

    result.requestPlan = requestPlanForInput(input, result.selectedServer);
    if (!result.requestPlan.ok) {
        const auto issue = input.operation == LiteWalletLifecycleOperation::OpenExisting
            ? LiteWalletServerLifecycleReadinessIssue::OpenWalletPathMissing
            : LiteWalletServerLifecycleReadinessIssue::RestoreSeedMissing;
        return stoppedResult(
            std::move(result),
            LiteWalletServerLifecycleReadinessStatus::WaitingForLifecycleUi,
            issue,
            result.requestPlan.error.empty()
                ? "lite wallet lifecycle UI request is incomplete"
                : result.requestPlan.error);
    }
    result.requestAccepted = true;

    if (options.requirePrivateDataRedaction && !input.ui.privateDataRedactionReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletServerLifecycleReadinessStatus::WaitingForPrivateDataRedaction,
            LiteWalletServerLifecycleReadinessIssue::PrivateDataRedactionMissing,
            "lite wallet lifecycle private-data redaction owner is not ready");
    }
    result.privateDataRedactionAccepted = true;

    if (options.requireSyncPlannerFeed && !input.ui.syncPlannerFeedReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletServerLifecycleReadinessStatus::WaitingForSyncPlannerFeed,
            LiteWalletServerLifecycleReadinessIssue::SyncPlannerFeedMissing,
            "lite lifecycle readiness feed for sync planners is not ready");
    }
    result.syncPlannerFeedAccepted = true;

    result.ok = true;
    result.status = LiteWalletServerLifecycleReadinessStatus::ReadyForFutureLifecycle;
    result.futureLifecycleCouldBeEnabled = true;
    result.lifecycleReportCouldFeedSyncPlanners = true;
    result.lifecycleStatus = readyLifecycleStatus(result.selectedServerDisplay);
    result.syncLifecycleInput.ready = true;
    result.syncLifecycleInput.status = result.lifecycleStatus;
    return result;
}

LiteWalletSyncAppRefreshLifecycleInput liteWalletSyncLifecycleInputFromServerLifecycleReadiness(
    const LiteWalletServerLifecycleReadinessResult& result)
{
    return result.syncLifecycleInput;
}

LiteWalletServerLifecycleReadinessPlanner::LiteWalletServerLifecycleReadinessPlanner(
    LiteWalletServerLifecycleReadinessOptions options)
    : options_(options)
{
}

LiteWalletServerLifecycleReadinessResult LiteWalletServerLifecycleReadinessPlanner::evaluate(
    const LiteWalletServerLifecycleReadinessInput& input) const
{
    return evaluateLiteWalletServerLifecycleReadiness(input, options_);
}

} // namespace dragonx::wallet