#include "wallet/lite_wallet_sync_execution_readiness.h"

#include <utility>

namespace dragonx::wallet {
namespace {

void addIssue(LiteWalletSyncExecutionReadinessResult& result,
              LiteWalletSyncExecutionReadinessIssue issue,
              std::string message)
{
    result.issues.push_back(LiteWalletSyncExecutionReadinessIssueInfo{issue, std::move(message)});
}

LiteWalletSyncExecutionReadinessResult stoppedResult(
    LiteWalletSyncExecutionReadinessResult result,
    LiteWalletSyncExecutionReadinessStatus status,
    LiteWalletSyncExecutionReadinessIssue issue,
    std::string message)
{
    result.status = status;
    addIssue(result, issue, std::move(message));
    result.error = result.issues.back().message;
    return result;
}

bool coreArtifactSymbolsReady(const LiteWalletSdxlArtifactSymbolsInput& symbols)
{
    return symbols.walletExists &&
           symbols.initializeNew &&
           symbols.initializeNewFromPhrase &&
           symbols.initializeExisting &&
           symbols.execute &&
           symbols.checkServerOnline;
}

bool integrationReportIsUnsafe(const LiteWalletSyncAppRefreshIntegrationResult& integration)
{
    return !integration.dryRunOnly ||
           !integration.noNetwork ||
           !integration.noBridgeCalls ||
           !integration.noSyncStarted ||
           !integration.noWalletPersistence ||
           integration.stateMutationAllowed ||
           integration.stateMutated ||
           integration.walletStateWritten ||
           integration.workerQueueEnqueued;
}

std::string backendMessageOrDefault(const WalletBackendStatus& status,
                                    const std::string& fallback)
{
    return status.message.empty() ? fallback : status.message;
}

bool recoveryRequiredByIntegration(const LiteWalletSyncAppRefreshIntegrationResult& integration)
{
    return integration.recoveryRequired ||
           integration.futureClearRequired ||
           integration.futureRescanRequired ||
           integration.futureRestartSyncRequired ||
           integration.requiresUserAttention;
}

bool cancellationRequiredByIntegration(const LiteWalletSyncAppRefreshIntegrationResult& integration)
{
    return integration.cancellationRequired ||
           integration.status == LiteWalletSyncAppRefreshIntegrationStatus::WaitingForCancellation;
}

void copyIntegrationSummary(LiteWalletSyncExecutionReadinessResult& result,
                            const LiteWalletSyncAppRefreshIntegrationResult& integration)
{
    result.integrationReport = integration;
    result.integrationFeedReady = integration.futureWorkerQueueFeedReady;
    result.recoveryRequired = recoveryRequiredByIntegration(integration);
    result.cancellationRequired = cancellationRequiredByIntegration(integration);
    result.futureClearRequired = integration.futureClearRequired;
    result.futureRescanRequired = integration.futureRescanRequired;
    result.futureRestartSyncRequired = integration.futureRestartSyncRequired;
    result.requiresUserAttention = integration.requiresUserAttention;
    result.enablementPlan.startSyncCommand = integration.syncStartPlan.command;
    result.enablementPlan.syncStatusCommand = integration.syncStatusPlan.command;
    result.enablementPlan.workerQueueLane = integration.futureWorkerQueuePlan.laneName;
    result.enablementPlan.route = integration.route;
}

LiteWalletSyncExecutionReadinessResult evaluateRecoveryReadiness(
    LiteWalletSyncExecutionReadinessResult result,
    const LiteWalletSyncExecutionRecoveryReadinessInput& recovery,
    LiteWalletSyncExecutionReadinessOptions options)
{
    if (!options.requireRecoveryExecutionReadiness) {
        result.recoveryExecutionReady = true;
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForRecovery,
            LiteWalletSyncExecutionReadinessIssue::IntegrationFeedNotReady,
            "lite sync recovery must complete before sync execution can be enabled");
    }

    if (result.futureClearRequired && !recovery.clearActionReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForRecovery,
            LiteWalletSyncExecutionReadinessIssue::RecoveryClearMissing,
            "lite sync recovery requires a future clear action before sync execution");
    }
    if (result.futureRescanRequired && !recovery.rescanActionReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForRecovery,
            LiteWalletSyncExecutionReadinessIssue::RecoveryRescanMissing,
            "lite sync recovery requires a future rescan action before sync execution");
    }
    if (result.futureRestartSyncRequired && !recovery.restartSyncActionReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForRecovery,
            LiteWalletSyncExecutionReadinessIssue::RecoveryRestartMissing,
            "lite sync recovery requires a future restart-sync action before sync execution");
    }
    if (result.requiresUserAttention && !recovery.userAttentionPathReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForRecovery,
            LiteWalletSyncExecutionReadinessIssue::RecoveryUserAttentionMissing,
            "lite sync recovery requires a user-attention path before sync execution");
    }

    result.recoveryExecutionReady = true;
    return stoppedResult(
        std::move(result),
        LiteWalletSyncExecutionReadinessStatus::WaitingForRecovery,
        LiteWalletSyncExecutionReadinessIssue::IntegrationFeedNotReady,
        "lite sync recovery is ready to be modeled but must complete before sync execution");
}

} // namespace

const char* liteWalletSyncExecutionReadinessStatusName(
    LiteWalletSyncExecutionReadinessStatus status)
{
    switch (status) {
        case LiteWalletSyncExecutionReadinessStatus::ReadyToEnableSyncExecution: return "ReadyToEnableSyncExecution";
        case LiteWalletSyncExecutionReadinessStatus::WaitingForLiteBuild: return "WaitingForLiteBuild";
        case LiteWalletSyncExecutionReadinessStatus::WaitingForArtifact: return "WaitingForArtifact";
        case LiteWalletSyncExecutionReadinessStatus::WaitingForBackendLink: return "WaitingForBackendLink";
        case LiteWalletSyncExecutionReadinessStatus::WaitingForBridge: return "WaitingForBridge";
        case LiteWalletSyncExecutionReadinessStatus::WaitingForIntegration: return "WaitingForIntegration";
        case LiteWalletSyncExecutionReadinessStatus::WaitingForExecutionOwner: return "WaitingForExecutionOwner";
        case LiteWalletSyncExecutionReadinessStatus::WaitingForCancellation: return "WaitingForCancellation";
        case LiteWalletSyncExecutionReadinessStatus::WaitingForShutdown: return "WaitingForShutdown";
        case LiteWalletSyncExecutionReadinessStatus::WaitingForRetry: return "WaitingForRetry";
        case LiteWalletSyncExecutionReadinessStatus::WaitingForRecovery: return "WaitingForRecovery";
        case LiteWalletSyncExecutionReadinessStatus::UnsafePlan: return "UnsafePlan";
    }
    return "Unknown";
}

const char* liteWalletSyncExecutionReadinessIssueName(
    LiteWalletSyncExecutionReadinessIssue issue)
{
    switch (issue) {
        case LiteWalletSyncExecutionReadinessIssue::FullNodeBuild: return "FullNodeBuild";
        case LiteWalletSyncExecutionReadinessIssue::LiteBackendCapabilityMissing: return "LiteBackendCapabilityMissing";
        case LiteWalletSyncExecutionReadinessIssue::ArtifactPathMissing: return "ArtifactPathMissing";
        case LiteWalletSyncExecutionReadinessIssue::ArtifactMissing: return "ArtifactMissing";
        case LiteWalletSyncExecutionReadinessIssue::ArtifactUnreadable: return "ArtifactUnreadable";
        case LiteWalletSyncExecutionReadinessIssue::ArtifactNotSdxlCompatible: return "ArtifactNotSdxlCompatible";
        case LiteWalletSyncExecutionReadinessIssue::ArtifactSymbolsMissing: return "ArtifactSymbolsMissing";
        case LiteWalletSyncExecutionReadinessIssue::ArtifactStringOwnershipUnverified: return "ArtifactStringOwnershipUnverified";
        case LiteWalletSyncExecutionReadinessIssue::ArtifactShutdownUnavailable: return "ArtifactShutdownUnavailable";
        case LiteWalletSyncExecutionReadinessIssue::BackendNotLinked: return "BackendNotLinked";
        case LiteWalletSyncExecutionReadinessIssue::BridgeUnavailable: return "BridgeUnavailable";
        case LiteWalletSyncExecutionReadinessIssue::IntegrationRejected: return "IntegrationRejected";
        case LiteWalletSyncExecutionReadinessIssue::IntegrationUnsafe: return "IntegrationUnsafe";
        case LiteWalletSyncExecutionReadinessIssue::IntegrationFeedNotReady: return "IntegrationFeedNotReady";
        case LiteWalletSyncExecutionReadinessIssue::WorkerQueueOwnerMissing: return "WorkerQueueOwnerMissing";
        case LiteWalletSyncExecutionReadinessIssue::SyncLoopOwnerMissing: return "SyncLoopOwnerMissing";
        case LiteWalletSyncExecutionReadinessIssue::StartSyncExecutionMissing: return "StartSyncExecutionMissing";
        case LiteWalletSyncExecutionReadinessIssue::SyncStatusExecutionMissing: return "SyncStatusExecutionMissing";
        case LiteWalletSyncExecutionReadinessIssue::CancellationPathMissing: return "CancellationPathMissing";
        case LiteWalletSyncExecutionReadinessIssue::CancellationPending: return "CancellationPending";
        case LiteWalletSyncExecutionReadinessIssue::ShutdownPathMissing: return "ShutdownPathMissing";
        case LiteWalletSyncExecutionReadinessIssue::ShutdownPending: return "ShutdownPending";
        case LiteWalletSyncExecutionReadinessIssue::RetryPolicyMissing: return "RetryPolicyMissing";
        case LiteWalletSyncExecutionReadinessIssue::RetryLimitReached: return "RetryLimitReached";
        case LiteWalletSyncExecutionReadinessIssue::UserVisibleStatusMissing: return "UserVisibleStatusMissing";
        case LiteWalletSyncExecutionReadinessIssue::RecoveryClearMissing: return "RecoveryClearMissing";
        case LiteWalletSyncExecutionReadinessIssue::RecoveryRescanMissing: return "RecoveryRescanMissing";
        case LiteWalletSyncExecutionReadinessIssue::RecoveryRestartMissing: return "RecoveryRestartMissing";
        case LiteWalletSyncExecutionReadinessIssue::RecoveryUserAttentionMissing: return "RecoveryUserAttentionMissing";
    }
    return "Unknown";
}

LiteWalletSyncExecutionReadinessResult evaluateLiteWalletSyncExecutionReadiness(
    const LiteWalletSyncExecutionReadinessInput& input,
    LiteWalletSyncExecutionReadinessOptions options)
{
    LiteWalletSyncExecutionReadinessResult result;
    result.capabilities = input.capabilities;
    result.backendStatus = input.backend.status;
    copyIntegrationSummary(result, input.integrationReport);

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

    if (options.requireLiteBackendCapability && !supportsLiteBackend(input.capabilities)) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForBackendLink,
            LiteWalletSyncExecutionReadinessIssue::LiteBackendCapabilityMissing,
            "lite backend capability is not available");
    }

    if (options.requireValidatedArtifact) {
        if (!input.artifact.pathConfigured || input.artifact.artifactPath.empty()) {
            return stoppedResult(
                std::move(result),
                LiteWalletSyncExecutionReadinessStatus::WaitingForArtifact,
                LiteWalletSyncExecutionReadinessIssue::ArtifactPathMissing,
                "SDXL-compatible lite backend artifact path is not configured");
        }
        if (!input.artifact.exists) {
            return stoppedResult(
                std::move(result),
                LiteWalletSyncExecutionReadinessStatus::WaitingForArtifact,
                LiteWalletSyncExecutionReadinessIssue::ArtifactMissing,
                "SDXL-compatible lite backend artifact does not exist");
        }
        if (!input.artifact.readable) {
            return stoppedResult(
                std::move(result),
                LiteWalletSyncExecutionReadinessStatus::WaitingForArtifact,
                LiteWalletSyncExecutionReadinessIssue::ArtifactUnreadable,
                "SDXL-compatible lite backend artifact is not readable");
        }
        if (!input.artifact.sdxlCompatible) {
            return stoppedResult(
                std::move(result),
                LiteWalletSyncExecutionReadinessStatus::WaitingForArtifact,
                LiteWalletSyncExecutionReadinessIssue::ArtifactNotSdxlCompatible,
                "lite backend artifact has not been validated as SDXL-compatible");
        }
        if (!coreArtifactSymbolsReady(input.artifact.symbols)) {
            return stoppedResult(
                std::move(result),
                LiteWalletSyncExecutionReadinessStatus::WaitingForArtifact,
                LiteWalletSyncExecutionReadinessIssue::ArtifactSymbolsMissing,
                "lite backend artifact is missing required SDXL lifecycle or execute symbols");
        }
        if (!input.artifact.symbols.freeString) {
            return stoppedResult(
                std::move(result),
                LiteWalletSyncExecutionReadinessStatus::WaitingForArtifact,
                LiteWalletSyncExecutionReadinessIssue::ArtifactStringOwnershipUnverified,
                "lite backend artifact string ownership cleanup is not validated");
        }
        if (!input.artifact.symbols.shutdown) {
            return stoppedResult(
                std::move(result),
                LiteWalletSyncExecutionReadinessStatus::WaitingForArtifact,
                LiteWalletSyncExecutionReadinessIssue::ArtifactShutdownUnavailable,
                "lite backend artifact shutdown symbol is not validated");
        }
    }
    result.artifactAccepted = true;

    if (options.requireLinkedBackend && !input.backend.linked) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForBackendLink,
            LiteWalletSyncExecutionReadinessIssue::BackendNotLinked,
            backendMessageOrDefault(input.backend.status, "lite backend is not linked"));
    }
    result.backendLinkedAccepted = true;

    if (options.requireBridgeAvailable && !input.backend.bridgeAvailable) {
        const auto message = !input.backend.bridgeUnavailableReason.empty()
            ? input.backend.bridgeUnavailableReason
            : backendMessageOrDefault(input.backend.status, "lite client bridge is unavailable");
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForBridge,
            LiteWalletSyncExecutionReadinessIssue::BridgeUnavailable,
            message);
    }
    result.bridgeAccepted = true;

    if (integrationReportIsUnsafe(input.integrationReport)) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::UnsafePlan,
            LiteWalletSyncExecutionReadinessIssue::IntegrationUnsafe,
            "lite sync/app-refresh integration report is not a no-network dry-run report");
    }

    if (result.recoveryRequired) {
        return evaluateRecoveryReadiness(std::move(result), input.recovery, options);
    }

    if (result.cancellationRequired || input.cancellation.cancellationRequested) {
        result.cancellationRequired = true;
        if (!input.cancellation.cancellationPathReady) {
            return stoppedResult(
                std::move(result),
                LiteWalletSyncExecutionReadinessStatus::WaitingForCancellation,
                LiteWalletSyncExecutionReadinessIssue::CancellationPathMissing,
                "lite sync cancellation path must be ready before sync execution");
        }
        if (!input.cancellation.cancellationComplete) {
            return stoppedResult(
                std::move(result),
                LiteWalletSyncExecutionReadinessStatus::WaitingForCancellation,
                LiteWalletSyncExecutionReadinessIssue::CancellationPending,
                "lite sync cancellation must complete before sync execution");
        }
    }

    if (!input.integrationReport.ok) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForIntegration,
            LiteWalletSyncExecutionReadinessIssue::IntegrationRejected,
            input.integrationReport.error.empty()
                ? "lite sync/app-refresh integration report is not successful"
                : input.integrationReport.error);
    }

    if (options.requireIntegrationFeedReady && !input.integrationReport.futureWorkerQueueFeedReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForIntegration,
            LiteWalletSyncExecutionReadinessIssue::IntegrationFeedNotReady,
            "lite sync/app-refresh integration report is not ready to feed future work");
    }
    result.integrationAccepted = true;

    if (options.requireWorkerQueueOwner && !input.ownership.workerQueueOwnerReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForExecutionOwner,
            LiteWalletSyncExecutionReadinessIssue::WorkerQueueOwnerMissing,
            "lite sync execution requires explicit worker queue ownership");
    }
    result.workerQueueOwnerAccepted = true;

    if (options.requireSyncLoopOwner && !input.ownership.syncLoopOwnerReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForExecutionOwner,
            LiteWalletSyncExecutionReadinessIssue::SyncLoopOwnerMissing,
            "lite sync execution requires explicit sync loop ownership");
    }
    result.syncLoopOwnerAccepted = true;

    if (options.requireStartSyncExecution && !input.ownership.startSyncExecutionReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForExecutionOwner,
            LiteWalletSyncExecutionReadinessIssue::StartSyncExecutionMissing,
            "lite sync start execution path is not ready");
    }
    result.startSyncExecutionReady = true;

    if (options.requireSyncStatusPolling && !input.ownership.syncStatusPollingReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForExecutionOwner,
            LiteWalletSyncExecutionReadinessIssue::SyncStatusExecutionMissing,
            "lite syncstatus polling execution path is not ready");
    }
    result.syncStatusPollingReady = true;

    if (options.requireCancellationPath && !input.cancellation.cancellationPathReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForCancellation,
            LiteWalletSyncExecutionReadinessIssue::CancellationPathMissing,
            "lite sync cancellation path must be ready before sync execution");
    }
    result.cancellationReady = true;

    if (options.requireShutdownHook && !input.shutdown.shutdownHookReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForShutdown,
            LiteWalletSyncExecutionReadinessIssue::ShutdownPathMissing,
            "lite sync shutdown hook must be ready before sync execution");
    }
    if (input.shutdown.shutdownRequested && !input.shutdown.shutdownComplete) {
        result.shutdownRequired = true;
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForShutdown,
            LiteWalletSyncExecutionReadinessIssue::ShutdownPending,
            "lite sync shutdown must complete before new sync execution");
    }
    result.shutdownReady = true;

    if (options.requireRetryPolicy && !input.retry.retryPolicyReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForRetry,
            LiteWalletSyncExecutionReadinessIssue::RetryPolicyMissing,
            "lite sync retry policy must be ready before sync execution");
    }
    result.retryReady = true;

    if (options.requireUserVisibleStatus && !input.ownership.userVisibleStatusReady) {
        return stoppedResult(
            std::move(result),
            LiteWalletSyncExecutionReadinessStatus::WaitingForRetry,
            LiteWalletSyncExecutionReadinessIssue::UserVisibleStatusMissing,
            "lite sync execution requires user-visible status reporting");
    }
    result.userVisibleStatusReady = true;

    if (input.retry.retryRequested) {
        result.retryRequired = true;
        if (input.retry.maxAttempts > 0 && input.retry.attempt >= input.retry.maxAttempts) {
            return stoppedResult(
                std::move(result),
                LiteWalletSyncExecutionReadinessStatus::WaitingForRetry,
                LiteWalletSyncExecutionReadinessIssue::RetryLimitReached,
                "lite sync retry limit has been reached");
        }
    }

    result.ok = true;
    result.status = LiteWalletSyncExecutionReadinessStatus::ReadyToEnableSyncExecution;
    result.syncExecutionCouldStart = true;
    result.syncStatusPollingCouldStart = true;
    result.executionWouldUseBridge = true;
    result.enablementPlan.readyToEnable = true;
    result.enablementPlan.startSyncExecutionEnabled = true;
    result.enablementPlan.syncStatusPollingEnabled = true;
    return result;
}

LiteWalletSyncExecutionReadinessPlanner::LiteWalletSyncExecutionReadinessPlanner(
    LiteWalletSyncExecutionReadinessOptions options)
    : options_(options)
{
}

LiteWalletSyncExecutionReadinessResult LiteWalletSyncExecutionReadinessPlanner::evaluate(
    const LiteWalletSyncExecutionReadinessInput& input) const
{
    return evaluateLiteWalletSyncExecutionReadiness(input, options_);
}

} // namespace dragonx::wallet