#include "wallet/lite_backend_artifact_resolver.h"

#include <algorithm>
#include <cctype>
#include <filesystem>
#include <fstream>
#include <system_error>
#include <utility>

namespace dragonx::wallet {
namespace {

namespace fs = std::filesystem;

struct CandidateInspectionResult {
    bool ok = false;
    LiteBackendArtifactResolverStatus status = LiteBackendArtifactResolverStatus::WaitingForArtifactCandidate;
    LiteBackendArtifactResolverIssue issue = LiteBackendArtifactResolverIssue::ArtifactMissing;
    std::string message;
    LiteBackendResolvedArtifact artifact;
    LiteWalletSdxlArtifactInput syncArtifactInput;
};

void addIssue(LiteBackendArtifactResolverResult& result,
              LiteBackendArtifactResolverIssue issue,
              std::string message)
{
    result.issues.push_back(LiteBackendArtifactResolverIssueInfo{issue, std::move(message)});
}

void addIssue(LiteBackendActivationReadinessResult& result,
              LiteBackendActivationReadinessIssue issue,
              std::string message)
{
    result.issues.push_back(LiteBackendActivationReadinessIssueInfo{issue, std::move(message)});
}

LiteBackendArtifactResolverResult stoppedResolverResult(
    LiteBackendArtifactResolverResult result,
    LiteBackendArtifactResolverStatus status,
    LiteBackendArtifactResolverIssue issue,
    std::string message)
{
    result.status = status;
    addIssue(result, issue, std::move(message));
    result.error = result.issues.back().message;
    return result;
}

LiteBackendActivationReadinessResult stoppedActivationResult(
    LiteBackendActivationReadinessResult result,
    LiteBackendActivationReadinessStatus status,
    LiteBackendActivationReadinessIssue issue,
    std::string message,
    WalletBackendState backendState = WalletBackendState::Unavailable)
{
    result.status = status;
    addIssue(result, issue, std::move(message));
    result.error = result.issues.back().message;
    result.connectionStatus = WalletBackendStatus{backendState, result.error, {}, {}, 0.0};
    return result;
}

std::string lowerCopy(const std::string& value)
{
    std::string lowered;
    lowered.reserve(value.size());
    for (const unsigned char character : value) {
        lowered.push_back(static_cast<char>(std::tolower(character)));
    }
    return lowered;
}

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);
}

std::string baseNameLower(const std::string& path)
{
    const auto slash = path.find_last_of("/\\");
    const std::string name = slash == std::string::npos ? path : path.substr(slash + 1);
    return lowerCopy(name);
}

bool endsWith(const std::string& value, const char* suffix)
{
    const std::string suffixValue(suffix);
    return value.size() >= suffixValue.size() &&
           value.compare(value.size() - suffixValue.size(), suffixValue.size(), suffixValue) == 0;
}

LiteBackendArtifactPlatform normalizePlatform(LiteBackendArtifactPlatform platform)
{
    return platform == LiteBackendArtifactPlatform::Current
        ? currentLiteBackendArtifactPlatform()
        : platform;
}

LiteBackendArtifactKind inferArtifactKind(const std::string& path)
{
    const std::string name = baseNameLower(path);
    if (endsWith(name, ".a") || endsWith(name, ".lib")) return LiteBackendArtifactKind::StaticLibrary;
    if (endsWith(name, ".so") || endsWith(name, ".dll") || endsWith(name, ".dylib")) {
        return LiteBackendArtifactKind::SharedLibrary;
    }
    if (endsWith(name, ".exe") || name == "silentdragonxlite" || name == "silentdragonx-lite") {
        return LiteBackendArtifactKind::Executable;
    }
    return LiteBackendArtifactKind::Unknown;
}

bool artifactKindSupported(LiteBackendArtifactKind kind)
{
    return kind == LiteBackendArtifactKind::StaticLibrary ||
           kind == LiteBackendArtifactKind::SharedLibrary ||
           kind == LiteBackendArtifactKind::Executable;
}

std::vector<std::string> defaultArtifactNames(LiteBackendArtifactPlatform platform,
                                              LiteBackendArtifactKind kind)
{
    const auto normalizedPlatform = normalizePlatform(platform);
    std::vector<std::string> names;

    const auto addNamesForKind = [&](LiteBackendArtifactKind artifactKind) {
        switch (normalizedPlatform) {
            case LiteBackendArtifactPlatform::Windows:
                if (artifactKind == LiteBackendArtifactKind::StaticLibrary) {
                    names.push_back("silentdragonxlite.lib");
                    names.push_back("libsilentdragonxlite.a");
                } else if (artifactKind == LiteBackendArtifactKind::SharedLibrary) {
                    names.push_back("silentdragonxlite.dll");
                } else if (artifactKind == LiteBackendArtifactKind::Executable) {
                    names.push_back("silentdragonxlite.exe");
                    names.push_back("silentdragonx-lite.exe");
                }
                break;
            case LiteBackendArtifactPlatform::MacOS:
                if (artifactKind == LiteBackendArtifactKind::StaticLibrary) {
                    names.push_back("libsilentdragonxlite.a");
                    names.push_back("silentdragonxlite.a");
                } else if (artifactKind == LiteBackendArtifactKind::SharedLibrary) {
                    names.push_back("libsilentdragonxlite.dylib");
                    names.push_back("silentdragonxlite.dylib");
                } else if (artifactKind == LiteBackendArtifactKind::Executable) {
                    names.push_back("silentdragonxlite");
                    names.push_back("silentdragonx-lite");
                }
                break;
            case LiteBackendArtifactPlatform::Linux:
            case LiteBackendArtifactPlatform::Current:
            case LiteBackendArtifactPlatform::Unknown:
                if (artifactKind == LiteBackendArtifactKind::StaticLibrary) {
                    names.push_back("silentdragonxlite.a");
                    names.push_back("libsilentdragonxlite.a");
                } else if (artifactKind == LiteBackendArtifactKind::SharedLibrary) {
                    names.push_back("libsilentdragonxlite.so");
                    names.push_back("silentdragonxlite.so");
                } else if (artifactKind == LiteBackendArtifactKind::Executable) {
                    names.push_back("silentdragonxlite");
                    names.push_back("silentdragonx-lite");
                }
                break;
        }
    };

    if (kind == LiteBackendArtifactKind::Unknown) {
        addNamesForKind(LiteBackendArtifactKind::StaticLibrary);
        addNamesForKind(LiteBackendArtifactKind::SharedLibrary);
        addNamesForKind(LiteBackendArtifactKind::Executable);
    } else {
        addNamesForKind(kind);
    }
    return names;
}

fs::path resolvePath(const std::string& projectRoot, const std::string& path)
{
    const fs::path value(path);
    if (value.is_absolute()) return value;
    const fs::path root = projectRoot.empty() ? fs::path(".") : fs::path(projectRoot);
    return root / value;
}

std::vector<LiteBackendArtifactCandidate> expandSearchRoots(
    const LiteBackendArtifactResolverInput& input,
    LiteBackendArtifactResolverResult& result,
    LiteBackendArtifactResolverOptions options)
{
    std::vector<LiteBackendArtifactCandidate> candidates;
    result.searchRootCount = input.searchRoots.size();

    for (const auto& root : input.searchRoots) {
        if (options.requireArtifactCandidates && !root.configured) {
            result = stoppedResolverResult(
                std::move(result),
                LiteBackendArtifactResolverStatus::WaitingForArtifactSearchRoot,
                LiteBackendArtifactResolverIssue::ArtifactSearchRootNotConfigured,
                "lite backend artifact search root is not configured");
            return {};
        }
        if (trimCopy(root.rootPath).empty()) {
            result = stoppedResolverResult(
                std::move(result),
                LiteBackendArtifactResolverStatus::WaitingForArtifactSearchRoot,
                LiteBackendArtifactResolverIssue::ArtifactSearchRootMissing,
                "lite backend artifact search root path is missing");
            return {};
        }

        const fs::path rootPath = resolvePath(input.projectRoot, root.rootPath);
        std::error_code error;
        if (!fs::exists(rootPath, error) || error) {
            result = stoppedResolverResult(
                std::move(result),
                LiteBackendArtifactResolverStatus::WaitingForArtifactSearchRoot,
                LiteBackendArtifactResolverIssue::ArtifactSearchRootMissing,
                "lite backend artifact search root does not exist");
            return {};
        }
        if (!fs::is_directory(rootPath, error) || error) {
            result = stoppedResolverResult(
                std::move(result),
                LiteBackendArtifactResolverStatus::WaitingForArtifactSearchRoot,
                LiteBackendArtifactResolverIssue::ArtifactSearchRootNotDirectory,
                "lite backend artifact search root is not a directory");
            return {};
        }

        const auto names = root.expectedArtifactNames.empty()
            ? defaultArtifactNames(root.platform, root.kind)
            : root.expectedArtifactNames;
        for (const auto& artifactName : names) {
            LiteBackendArtifactCandidate candidate;
            candidate.configured = true;
            candidate.artifactPath = (rootPath / artifactName).string();
            candidate.platform = root.platform;
            candidate.kind = root.kind;
            candidate.versionLabel = root.versionLabel;
            candidate.provenance = root.provenance;
            candidate.signatureVerification = root.signatureVerification;
            candidate.sdxlCompatible = root.sdxlCompatible;
            candidate.symbols = root.symbols;
            candidate.executableMetadataRequired = root.executableMetadataRequired;
            candidates.push_back(std::move(candidate));
        }
    }
    result.artifactSearchRootsAccepted = true;
    return candidates;
}

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

bool fileReadable(const fs::path& path)
{
    std::ifstream input(path, std::ios::binary);
    return input.good();
}

bool fileExecutable(const fs::path& path, LiteBackendArtifactPlatform platform)
{
    const std::string name = baseNameLower(path.string());
    if (normalizePlatform(platform) == LiteBackendArtifactPlatform::Windows && endsWith(name, ".exe")) return true;

    std::error_code error;
    const auto permissions = fs::status(path, error).permissions();
    if (error) return false;
    return (permissions & fs::perms::owner_exec) != fs::perms::none ||
           (permissions & fs::perms::group_exec) != fs::perms::none ||
           (permissions & fs::perms::others_exec) != fs::perms::none;
}

bool provenanceComplete(const LiteBackendArtifactProvenanceMetadata& provenance)
{
    return provenance.metadataProvided &&
           !trimCopy(provenance.source).empty() &&
           !trimCopy(provenance.builder).empty() &&
           !trimCopy(provenance.sourceRevision).empty() &&
           !trimCopy(provenance.artifactSetId).empty();
}

CandidateInspectionResult inspectCandidate(const LiteBackendArtifactResolverInput& input,
                                           const LiteBackendArtifactCandidate& candidate,
                                           LiteBackendArtifactResolverOptions options)
{
    CandidateInspectionResult inspection;
    if (options.requireArtifactCandidates && !candidate.configured) {
        inspection.issue = LiteBackendArtifactResolverIssue::ArtifactCandidateNotConfigured;
        inspection.message = "lite backend artifact candidate is not configured";
        return inspection;
    }
    if (trimCopy(candidate.artifactPath).empty()) {
        inspection.issue = LiteBackendArtifactResolverIssue::ArtifactPathMissing;
        inspection.message = "lite backend artifact candidate path is missing";
        return inspection;
    }

    const fs::path artifactPath = resolvePath(input.projectRoot, candidate.artifactPath);
    std::error_code error;
    if (!fs::exists(artifactPath, error) || error) {
        inspection.issue = LiteBackendArtifactResolverIssue::ArtifactMissing;
        inspection.message = "lite backend artifact candidate does not exist";
        return inspection;
    }
    if (!fs::is_regular_file(artifactPath, error) || error) {
        inspection.issue = LiteBackendArtifactResolverIssue::ArtifactNotRegularFile;
        inspection.message = "lite backend artifact candidate is not a regular file";
        return inspection;
    }
    if (!fileReadable(artifactPath)) {
        inspection.issue = LiteBackendArtifactResolverIssue::ArtifactUnreadable;
        inspection.message = "lite backend artifact candidate is not readable";
        return inspection;
    }

    const auto candidatePlatform = normalizePlatform(candidate.platform);
    const auto expectedPlatform = normalizePlatform(input.expectedPlatform);
    if (candidatePlatform == LiteBackendArtifactPlatform::Unknown || candidatePlatform != expectedPlatform) {
        inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata;
        inspection.issue = LiteBackendArtifactResolverIssue::PlatformMismatch;
        inspection.message = "lite backend artifact platform metadata does not match the expected platform";
        return inspection;
    }

    const auto kind = candidate.kind == LiteBackendArtifactKind::Unknown
        ? inferArtifactKind(candidate.artifactPath)
        : candidate.kind;
    if (!artifactKindSupported(kind)) {
        inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata;
        inspection.issue = LiteBackendArtifactResolverIssue::UnsupportedArtifactKind;
        inspection.message = "lite backend artifact kind is unsupported or unknown";
        return inspection;
    }

    if (options.requireVersionMetadata && trimCopy(candidate.versionLabel).empty()) {
        inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata;
        inspection.issue = LiteBackendArtifactResolverIssue::VersionMissing;
        inspection.message = "lite backend artifact version metadata is missing";
        return inspection;
    }

    if (options.requireProvenanceMetadata) {
        if (!candidate.provenance.ownerReady) {
            inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata;
            inspection.issue = LiteBackendArtifactResolverIssue::ProvenanceOwnerMissing;
            inspection.message = "lite backend artifact provenance owner is not ready";
            return inspection;
        }
        if (!provenanceComplete(candidate.provenance)) {
            inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata;
            inspection.issue = LiteBackendArtifactResolverIssue::ProvenanceMetadataMissing;
            inspection.message = "lite backend artifact provenance metadata is incomplete";
            return inspection;
        }
    }

    if (options.requireSdxlCompatibility && !candidate.sdxlCompatible) {
        inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata;
        inspection.issue = LiteBackendArtifactResolverIssue::ArtifactNotSdxlCompatible;
        inspection.message = "lite backend artifact is not marked SDXL-compatible";
        return inspection;
    }

    if (options.requireSdxlSymbols) {
        if (!coreSymbolsReady(candidate.symbols)) {
            inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata;
            inspection.issue = LiteBackendArtifactResolverIssue::ArtifactSymbolsMissing;
            inspection.message = "lite backend artifact is missing required SDXL bridge symbol metadata";
            return inspection;
        }
        if (!candidate.symbols.freeString) {
            inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata;
            inspection.issue = LiteBackendArtifactResolverIssue::ArtifactStringOwnershipUnverified;
            inspection.message = "lite backend artifact string cleanup symbol metadata is missing";
            return inspection;
        }
        if (!candidate.symbols.shutdown) {
            inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata;
            inspection.issue = LiteBackendArtifactResolverIssue::ArtifactShutdownUnavailable;
            inspection.message = "lite backend artifact shutdown symbol metadata is missing";
            return inspection;
        }
    }

    const bool executable = fileExecutable(artifactPath, candidatePlatform);
    if ((kind == LiteBackendArtifactKind::Executable || candidate.executableMetadataRequired) && !executable) {
        inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata;
        inspection.issue = LiteBackendArtifactResolverIssue::ExecutableMetadataMissing;
        inspection.message = "lite backend executable artifact is not marked executable";
        return inspection;
    }

    std::size_t artifactSizeBytes = 0;
    const auto fileSize = fs::file_size(artifactPath, error);
    if (!error) artifactSizeBytes = static_cast<std::size_t>(fileSize);

    inspection.ok = true;
    inspection.artifact.found = true;
    inspection.artifact.artifactPath = artifactPath.string();
    inspection.artifact.platform = candidatePlatform;
    inspection.artifact.kind = kind;
    inspection.artifact.versionLabel = candidate.versionLabel;
    inspection.artifact.provenance = candidate.provenance;
    inspection.artifact.signatureVerification = candidate.signatureVerification;
    inspection.artifact.exists = true;
    inspection.artifact.regularFile = true;
    inspection.artifact.readable = true;
    inspection.artifact.executable = executable;
    inspection.artifact.sdxlCompatible = candidate.sdxlCompatible;
    inspection.artifact.symbols = candidate.symbols;
    inspection.artifact.artifactSizeBytes = artifactSizeBytes;

    inspection.syncArtifactInput.pathConfigured = true;
    inspection.syncArtifactInput.exists = true;
    inspection.syncArtifactInput.readable = true;
    inspection.syncArtifactInput.sdxlCompatible = candidate.sdxlCompatible;
    inspection.syncArtifactInput.artifactPath = artifactPath.string();
    inspection.syncArtifactInput.versionLabel = candidate.versionLabel;
    inspection.syncArtifactInput.symbols = candidate.symbols;
    return inspection;
}

LiteBackendArtifactResolverResult rejectResolverRuntimeAction(
    LiteBackendArtifactResolverResult result,
    const LiteBackendArtifactResolverInput& input,
    LiteBackendArtifactResolverOptions options)
{
    if (options.rejectArtifactMutation && input.artifactMutationRequested) {
        return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled,
                                     LiteBackendArtifactResolverIssue::ArtifactMutationRequested,
                                     "lite backend artifact mutation is disabled for artifact resolution");
    }
    if (options.rejectSdxlApiCalls && input.sdxlApiRequested) {
        return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled,
                                     LiteBackendArtifactResolverIssue::SdxlApiRequested,
                                     "SDXL API calls are disabled for artifact resolution");
    }
    if (options.rejectServerConnectivityChecks && input.serverConnectivityCheckRequested) {
        return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled,
                                     LiteBackendArtifactResolverIssue::ServerConnectivityCheckRequested,
                                     "server connectivity checks are disabled for artifact resolution");
    }
    if (options.rejectWalletLifecycle && input.walletLifecycleRequested) {
        return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled,
                                     LiteBackendArtifactResolverIssue::WalletLifecycleRequested,
                                     "wallet lifecycle execution is disabled for artifact resolution");
    }
    if (options.rejectSync && input.syncRequested) {
        return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled,
                                     LiteBackendArtifactResolverIssue::SyncRequested,
                                     "lite sync execution is disabled for artifact resolution");
    }
    if (options.rejectSyncStatusPolling && input.syncStatusPollingRequested) {
        return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled,
                                     LiteBackendArtifactResolverIssue::SyncStatusPollingRequested,
                                     "lite syncstatus polling is disabled for artifact resolution");
    }
    if (options.rejectWorkerQueue && input.workerQueueRequested) {
        return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled,
                                     LiteBackendArtifactResolverIssue::WorkerQueueRequested,
                                     "worker queue enqueue is disabled for artifact resolution");
    }
    if (options.rejectWalletStateMutation && input.walletStateMutationRequested) {
        return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled,
                                     LiteBackendArtifactResolverIssue::WalletStateMutationRequested,
                                     "WalletState mutation is disabled for artifact resolution");
    }
    if (options.rejectWalletPersistence && input.walletPersistenceRequested) {
        return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled,
                                     LiteBackendArtifactResolverIssue::WalletPersistenceRequested,
                                     "wallet persistence is disabled for artifact resolution");
    }
    if (options.rejectUpload && input.uploadRequested) {
        return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled,
                                     LiteBackendArtifactResolverIssue::UploadRequested,
                                     "upload is disabled for artifact resolution");
    }
    if (options.rejectSigning && input.signingRequested) {
        return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled,
                                     LiteBackendArtifactResolverIssue::SigningRequested,
                                     "signing is disabled for artifact resolution");
    }
    if (options.rejectPublication && input.publicationRequested) {
        return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled,
                                     LiteBackendArtifactResolverIssue::PublicationRequested,
                                     "publication is disabled for artifact resolution");
    }
    return result;
}

LiteBackendActivationReadinessResult rejectActivationRuntimeAction(
    LiteBackendActivationReadinessResult result,
    const LiteBackendActivationReadinessInput& input,
    LiteBackendActivationReadinessOptions options)
{
    if (options.rejectArtifactMutation && input.artifactMutationRequested) {
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled,
                                       LiteBackendActivationReadinessIssue::ArtifactMutationRequested,
                                       "lite backend artifact mutation is disabled for activation readiness");
    }
    if (options.rejectSdxlApiCalls && input.sdxlApiRequested) {
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled,
                                       LiteBackendActivationReadinessIssue::SdxlApiRequested,
                                       "SDXL API calls are disabled for activation readiness");
    }
    if (options.rejectServerConnectivityChecks && input.serverConnectivityCheckRequested) {
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled,
                                       LiteBackendActivationReadinessIssue::ServerConnectivityCheckRequested,
                                       "server connectivity checks are disabled for activation readiness");
    }
    if (options.rejectWalletLifecycle && input.walletLifecycleRequested) {
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled,
                                       LiteBackendActivationReadinessIssue::WalletLifecycleRequested,
                                       "wallet lifecycle execution is disabled for activation readiness");
    }
    if (options.rejectSync && input.syncRequested) {
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled,
                                       LiteBackendActivationReadinessIssue::SyncRequested,
                                       "lite sync execution is disabled for activation readiness");
    }
    if (options.rejectSyncStatusPolling && input.syncStatusPollingRequested) {
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled,
                                       LiteBackendActivationReadinessIssue::SyncStatusPollingRequested,
                                       "lite syncstatus polling is disabled for activation readiness");
    }
    if (options.rejectWorkerQueue && input.workerQueueRequested) {
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled,
                                       LiteBackendActivationReadinessIssue::WorkerQueueRequested,
                                       "worker queue enqueue is disabled for activation readiness");
    }
    if (options.rejectWalletStateMutation && input.walletStateMutationRequested) {
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled,
                                       LiteBackendActivationReadinessIssue::WalletStateMutationRequested,
                                       "WalletState mutation is disabled for activation readiness");
    }
    if (options.rejectWalletPersistence && input.walletPersistenceRequested) {
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled,
                                       LiteBackendActivationReadinessIssue::WalletPersistenceRequested,
                                       "wallet persistence is disabled for activation readiness");
    }
    if (options.rejectUpload && input.uploadRequested) {
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled,
                                       LiteBackendActivationReadinessIssue::UploadRequested,
                                       "upload is disabled for activation readiness");
    }
    if (options.rejectSigning && input.signingRequested) {
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled,
                                       LiteBackendActivationReadinessIssue::SigningRequested,
                                       "signing is disabled for activation readiness");
    }
    if (options.rejectPublication && input.publicationRequested) {
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled,
                                       LiteBackendActivationReadinessIssue::PublicationRequested,
                                       "publication is disabled for activation readiness");
    }
    return result;
}

WalletBackendStatus backendStatusOrDefault(const LiteBackendBridgeReadinessInput& backend,
                                           const std::string& fallback)
{
    if (!backend.status.message.empty()) return backend.status;
    return WalletBackendStatus{WalletBackendState::Unavailable, fallback, {}, {}, 0.0};
}

WalletBackendStatus readyConnectionStatus(const LiteServerSelectionResult& selectedServer)
{
    const std::string serverLabel = selectedServer.server.label.empty()
        ? selectedServer.server.url
        : selectedServer.server.label;
    return WalletBackendStatus{
        WalletBackendState::Disconnected,
        "lite backend activation readiness accepted for " + serverLabel + "; bridge calls remain disabled here",
        {},
        {},
        0.0
    };
}

} // namespace

LiteBackendArtifactPlatform currentLiteBackendArtifactPlatform()
{
#if defined(_WIN32)
    return LiteBackendArtifactPlatform::Windows;
#elif defined(__APPLE__)
    return LiteBackendArtifactPlatform::MacOS;
#else
    return LiteBackendArtifactPlatform::Linux;
#endif
}

const char* liteBackendArtifactPlatformName(LiteBackendArtifactPlatform platform)
{
    switch (platform) {
        case LiteBackendArtifactPlatform::Current: return "Current";
        case LiteBackendArtifactPlatform::Linux: return "Linux";
        case LiteBackendArtifactPlatform::Windows: return "Windows";
        case LiteBackendArtifactPlatform::MacOS: return "MacOS";
        case LiteBackendArtifactPlatform::Unknown: return "Unknown";
    }
    return "Unknown";
}

const char* liteBackendArtifactKindName(LiteBackendArtifactKind kind)
{
    switch (kind) {
        case LiteBackendArtifactKind::Unknown: return "Unknown";
        case LiteBackendArtifactKind::StaticLibrary: return "StaticLibrary";
        case LiteBackendArtifactKind::SharedLibrary: return "SharedLibrary";
        case LiteBackendArtifactKind::Executable: return "Executable";
    }
    return "Unknown";
}

const char* liteBackendArtifactResolverStatusName(LiteBackendArtifactResolverStatus status)
{
    switch (status) {
        case LiteBackendArtifactResolverStatus::ReadyForActivationReadiness: return "ReadyForActivationReadiness";
        case LiteBackendArtifactResolverStatus::WaitingForResolverOwner: return "WaitingForResolverOwner";
        case LiteBackendArtifactResolverStatus::WaitingForReadOnlyGate: return "WaitingForReadOnlyGate";
        case LiteBackendArtifactResolverStatus::WaitingForArtifactSearchRoot: return "WaitingForArtifactSearchRoot";
        case LiteBackendArtifactResolverStatus::WaitingForArtifactCandidate: return "WaitingForArtifactCandidate";
        case LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata: return "WaitingForArtifactMetadata";
        case LiteBackendArtifactResolverStatus::RuntimeActionDisabled: return "RuntimeActionDisabled";
    }
    return "Unknown";
}

const char* liteBackendArtifactResolverIssueName(LiteBackendArtifactResolverIssue issue)
{
    switch (issue) {
        case LiteBackendArtifactResolverIssue::ResolverOwnerMissing: return "ResolverOwnerMissing";
        case LiteBackendArtifactResolverIssue::ReadOnlyGateMissing: return "ReadOnlyGateMissing";
        case LiteBackendArtifactResolverIssue::ArtifactSearchRootMissing: return "ArtifactSearchRootMissing";
        case LiteBackendArtifactResolverIssue::ArtifactSearchRootNotConfigured: return "ArtifactSearchRootNotConfigured";
        case LiteBackendArtifactResolverIssue::ArtifactSearchRootNotDirectory: return "ArtifactSearchRootNotDirectory";
        case LiteBackendArtifactResolverIssue::ArtifactCandidateMissing: return "ArtifactCandidateMissing";
        case LiteBackendArtifactResolverIssue::ArtifactCandidateNotConfigured: return "ArtifactCandidateNotConfigured";
        case LiteBackendArtifactResolverIssue::ArtifactPathMissing: return "ArtifactPathMissing";
        case LiteBackendArtifactResolverIssue::ArtifactMissing: return "ArtifactMissing";
        case LiteBackendArtifactResolverIssue::ArtifactNotRegularFile: return "ArtifactNotRegularFile";
        case LiteBackendArtifactResolverIssue::ArtifactUnreadable: return "ArtifactUnreadable";
        case LiteBackendArtifactResolverIssue::UnsupportedArtifactKind: return "UnsupportedArtifactKind";
        case LiteBackendArtifactResolverIssue::PlatformMismatch: return "PlatformMismatch";
        case LiteBackendArtifactResolverIssue::VersionMissing: return "VersionMissing";
        case LiteBackendArtifactResolverIssue::ProvenanceOwnerMissing: return "ProvenanceOwnerMissing";
        case LiteBackendArtifactResolverIssue::ProvenanceMetadataMissing: return "ProvenanceMetadataMissing";
        case LiteBackendArtifactResolverIssue::ArtifactNotSdxlCompatible: return "ArtifactNotSdxlCompatible";
        case LiteBackendArtifactResolverIssue::ArtifactSymbolsMissing: return "ArtifactSymbolsMissing";
        case LiteBackendArtifactResolverIssue::ArtifactStringOwnershipUnverified: return "ArtifactStringOwnershipUnverified";
        case LiteBackendArtifactResolverIssue::ArtifactShutdownUnavailable: return "ArtifactShutdownUnavailable";
        case LiteBackendArtifactResolverIssue::ExecutableMetadataMissing: return "ExecutableMetadataMissing";
        case LiteBackendArtifactResolverIssue::ArtifactMutationRequested: return "ArtifactMutationRequested";
        case LiteBackendArtifactResolverIssue::SdxlApiRequested: return "SdxlApiRequested";
        case LiteBackendArtifactResolverIssue::ServerConnectivityCheckRequested: return "ServerConnectivityCheckRequested";
        case LiteBackendArtifactResolverIssue::WalletLifecycleRequested: return "WalletLifecycleRequested";
        case LiteBackendArtifactResolverIssue::SyncRequested: return "SyncRequested";
        case LiteBackendArtifactResolverIssue::SyncStatusPollingRequested: return "SyncStatusPollingRequested";
        case LiteBackendArtifactResolverIssue::WorkerQueueRequested: return "WorkerQueueRequested";
        case LiteBackendArtifactResolverIssue::WalletStateMutationRequested: return "WalletStateMutationRequested";
        case LiteBackendArtifactResolverIssue::WalletPersistenceRequested: return "WalletPersistenceRequested";
        case LiteBackendArtifactResolverIssue::UploadRequested: return "UploadRequested";
        case LiteBackendArtifactResolverIssue::SigningRequested: return "SigningRequested";
        case LiteBackendArtifactResolverIssue::PublicationRequested: return "PublicationRequested";
    }
    return "Unknown";
}

const char* liteBackendActivationReadinessStatusName(LiteBackendActivationReadinessStatus status)
{
    switch (status) {
        case LiteBackendActivationReadinessStatus::ReadyForConnectionReadiness: return "ReadyForConnectionReadiness";
        case LiteBackendActivationReadinessStatus::WaitingForActivationOwner: return "WaitingForActivationOwner";
        case LiteBackendActivationReadinessStatus::WaitingForReadOnlyGate: return "WaitingForReadOnlyGate";
        case LiteBackendActivationReadinessStatus::WaitingForLiteBuild: return "WaitingForLiteBuild";
        case LiteBackendActivationReadinessStatus::WaitingForBackendCapability: return "WaitingForBackendCapability";
        case LiteBackendActivationReadinessStatus::WaitingForArtifactResolver: return "WaitingForArtifactResolver";
        case LiteBackendActivationReadinessStatus::WaitingForBackendLink: return "WaitingForBackendLink";
        case LiteBackendActivationReadinessStatus::WaitingForBridge: return "WaitingForBridge";
        case LiteBackendActivationReadinessStatus::WaitingForConnectionSettings: return "WaitingForConnectionSettings";
        case LiteBackendActivationReadinessStatus::RuntimeActionDisabled: return "RuntimeActionDisabled";
    }
    return "Unknown";
}

const char* liteBackendActivationReadinessIssueName(LiteBackendActivationReadinessIssue issue)
{
    switch (issue) {
        case LiteBackendActivationReadinessIssue::ActivationOwnerMissing: return "ActivationOwnerMissing";
        case LiteBackendActivationReadinessIssue::ReadOnlyGateMissing: return "ReadOnlyGateMissing";
        case LiteBackendActivationReadinessIssue::FullNodeBuild: return "FullNodeBuild";
        case LiteBackendActivationReadinessIssue::LiteBackendCapabilityMissing: return "LiteBackendCapabilityMissing";
        case LiteBackendActivationReadinessIssue::ArtifactResolverRejected: return "ArtifactResolverRejected";
        case LiteBackendActivationReadinessIssue::BackendNotLinked: return "BackendNotLinked";
        case LiteBackendActivationReadinessIssue::BridgeUnavailable: return "BridgeUnavailable";
        case LiteBackendActivationReadinessIssue::ConnectionSettingsRejected: return "ConnectionSettingsRejected";
        case LiteBackendActivationReadinessIssue::ArtifactMutationRequested: return "ArtifactMutationRequested";
        case LiteBackendActivationReadinessIssue::SdxlApiRequested: return "SdxlApiRequested";
        case LiteBackendActivationReadinessIssue::ServerConnectivityCheckRequested: return "ServerConnectivityCheckRequested";
        case LiteBackendActivationReadinessIssue::WalletLifecycleRequested: return "WalletLifecycleRequested";
        case LiteBackendActivationReadinessIssue::SyncRequested: return "SyncRequested";
        case LiteBackendActivationReadinessIssue::SyncStatusPollingRequested: return "SyncStatusPollingRequested";
        case LiteBackendActivationReadinessIssue::WorkerQueueRequested: return "WorkerQueueRequested";
        case LiteBackendActivationReadinessIssue::WalletStateMutationRequested: return "WalletStateMutationRequested";
        case LiteBackendActivationReadinessIssue::WalletPersistenceRequested: return "WalletPersistenceRequested";
        case LiteBackendActivationReadinessIssue::UploadRequested: return "UploadRequested";
        case LiteBackendActivationReadinessIssue::SigningRequested: return "SigningRequested";
        case LiteBackendActivationReadinessIssue::PublicationRequested: return "PublicationRequested";
    }
    return "Unknown";
}

LiteBackendArtifactResolverResult evaluateLiteBackendArtifactResolver(
    const LiteBackendArtifactResolverInput& input,
    LiteBackendArtifactResolverOptions options)
{
    LiteBackendArtifactResolverResult result;

    result = rejectResolverRuntimeAction(std::move(result), input, options);
    if (!result.issues.empty()) return result;

    if (options.requireResolverOwner && !input.resolverOwnerReady) {
        return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::WaitingForResolverOwner,
                                     LiteBackendArtifactResolverIssue::ResolverOwnerMissing,
                                     "lite backend artifact resolver owner is not ready");
    }
    result.resolverOwnerAccepted = true;

    if (options.requireReadOnlyGate && !input.readOnlyGateReady) {
        return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::WaitingForReadOnlyGate,
                                     LiteBackendArtifactResolverIssue::ReadOnlyGateMissing,
                                     "lite backend artifact resolver read-only gate is not ready");
    }
    result.readOnlyGateAccepted = true;

    auto candidates = expandSearchRoots(input, result, options);
    if (!result.issues.empty()) return result;
    for (const auto& candidate : input.candidates) candidates.push_back(candidate);

    result.candidateCount = candidates.size();
    if (options.requireArtifactCandidates && candidates.empty()) {
        return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::WaitingForArtifactCandidate,
                                     LiteBackendArtifactResolverIssue::ArtifactCandidateMissing,
                                     "lite backend artifact resolver has no configured candidates");
    }
    result.artifactCandidatesAccepted = true;

    CandidateInspectionResult firstRejected;
    bool haveRejectedCandidate = false;
    for (const auto& candidate : candidates) {
        ++result.checkedCandidateCount;
        auto inspection = inspectCandidate(input, candidate, options);
        if (!inspection.ok) {
            ++result.rejectedCandidateCount;
            if (!haveRejectedCandidate) {
                firstRejected = std::move(inspection);
                haveRejectedCandidate = true;
            }
            continue;
        }

        result.ok = true;
        result.status = LiteBackendArtifactResolverStatus::ReadyForActivationReadiness;
        result.artifact = std::move(inspection.artifact);
        result.syncArtifactInput = std::move(inspection.syncArtifactInput);
        result.artifactDiscovered = true;
        result.artifactMetadataAccepted = true;
        result.platformAccepted = true;
        result.versionAccepted = !options.requireVersionMetadata || !result.artifact.versionLabel.empty();
        result.provenanceAccepted = !options.requireProvenanceMetadata || provenanceComplete(result.artifact.provenance);
        result.sdxlCompatibilityAccepted = !options.requireSdxlCompatibility || result.artifact.sdxlCompatible;
        result.symbolMetadataAccepted = !options.requireSdxlSymbols ||
            (coreSymbolsReady(result.artifact.symbols) && result.artifact.symbols.freeString && result.artifact.symbols.shutdown);
        result.executableMetadataAccepted = true;
        result.syncArtifactInputProduced = true;
        return result;
    }

    if (haveRejectedCandidate) {
        return stoppedResolverResult(std::move(result), firstRejected.status, firstRejected.issue, firstRejected.message);
    }
    return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::WaitingForArtifactCandidate,
                                 LiteBackendArtifactResolverIssue::ArtifactCandidateMissing,
                                 "lite backend artifact resolver did not find any artifact candidates");
}

LiteBackendActivationReadinessResult evaluateLiteBackendActivationReadiness(
    const LiteBackendActivationReadinessInput& input,
    LiteBackendActivationReadinessOptions options)
{
    LiteBackendActivationReadinessResult result;
    result.connectionAvailability = LiteConnectionAvailability::BackendUnavailable;

    result = rejectActivationRuntimeAction(std::move(result), input, options);
    if (!result.issues.empty()) return result;

    if (options.requireActivationOwner && !input.activationOwnerReady) {
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::WaitingForActivationOwner,
                                       LiteBackendActivationReadinessIssue::ActivationOwnerMissing,
                                       "lite backend activation readiness owner is not ready");
    }
    result.activationOwnerAccepted = true;

    if (options.requireReadOnlyGate && !input.readOnlyGateReady) {
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::WaitingForReadOnlyGate,
                                       LiteBackendActivationReadinessIssue::ReadOnlyGateMissing,
                                       "lite backend activation readiness read-only gate is not ready");
    }
    result.readOnlyGateAccepted = true;

    if (options.requireLiteBuild && !isLiteBuild(input.capabilities)) {
        result.connectionAvailability = LiteConnectionAvailability::UnsupportedBuild;
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::WaitingForLiteBuild,
                                       LiteBackendActivationReadinessIssue::FullNodeBuild,
                                       "lite backend activation readiness requires a lite build");
    }
    result.liteBuildAccepted = true;

    if (options.requireLiteBackendCapability && !supportsLiteBackend(input.capabilities)) {
        result.connectionAvailability = LiteConnectionAvailability::BackendUnavailable;
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::WaitingForBackendCapability,
                                       LiteBackendActivationReadinessIssue::LiteBackendCapabilityMissing,
                                       "lite backend capability is not available for activation readiness");
    }
    result.backendCapabilityAccepted = true;

    result.artifactResolverResult = evaluateLiteBackendArtifactResolver(input.artifactResolver, options.resolverOptions);
    if (options.requireResolvedArtifact && !result.artifactResolverResult.ok) {
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::WaitingForArtifactResolver,
                                       LiteBackendActivationReadinessIssue::ArtifactResolverRejected,
                                       result.artifactResolverResult.error.empty()
                                           ? "lite backend artifact resolver did not produce a usable artifact"
                                           : result.artifactResolverResult.error);
    }
    result.artifactResolverAccepted = true;
    result.syncArtifactInput = result.artifactResolverResult.syncArtifactInput;

    if (options.requireLinkedBackend && !input.backend.linked) {
        result.connectionAvailability = LiteConnectionAvailability::BackendUnavailable;
        const auto status = backendStatusOrDefault(input.backend, "lite backend is not linked");
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::WaitingForBackendLink,
                                       LiteBackendActivationReadinessIssue::BackendNotLinked,
                                       status.message);
    }
    result.backendLinkedAccepted = true;

    if (options.requireBridgeAvailable && !input.backend.bridgeAvailable) {
        result.connectionAvailability = LiteConnectionAvailability::BridgeUnavailable;
        const std::string message = !input.backend.bridgeUnavailableReason.empty()
            ? input.backend.bridgeUnavailableReason
            : backendStatusOrDefault(input.backend, "lite client bridge is unavailable").message;
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::WaitingForBridge,
                                       LiteBackendActivationReadinessIssue::BridgeUnavailable,
                                       message);
    }
    result.bridgeAccepted = true;

    result.selectedServer = selectLiteServer(input.connectionSettings);
    if (options.requireUsableServer && !result.selectedServer.ok) {
        result.connectionAvailability = LiteConnectionAvailability::NoUsableServer;
        return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::WaitingForConnectionSettings,
                                       LiteBackendActivationReadinessIssue::ConnectionSettingsRejected,
                                       result.selectedServer.error.empty()
                                           ? "no usable lite server is configured for activation readiness"
                                           : result.selectedServer.error,
                                       WalletBackendState::Error);
    }
    result.connectionSettingsAccepted = true;

    result.syncBackendInput.linked = input.backend.linked;
    result.syncBackendInput.bridgeAvailable = input.backend.bridgeAvailable;
    result.syncBackendInput.status = input.backend.status.message.empty()
        ? WalletBackendStatus{WalletBackendState::Disconnected, "lite backend bridge readiness accepted", {}, {}, 0.0}
        : input.backend.status;
    result.syncBackendInput.bridgeUnavailableReason = input.backend.bridgeUnavailableReason;
    result.syncReadinessInputsProduced = true;

    result.ok = true;
    result.status = LiteBackendActivationReadinessStatus::ReadyForConnectionReadiness;
    result.connectionAvailability = LiteConnectionAvailability::Ready;
    result.connectionStatus = readyConnectionStatus(result.selectedServer);
    result.connectionServiceBoundaryAccepted = true;
    return result;
}

LiteBackendArtifactResolver::LiteBackendArtifactResolver(LiteBackendArtifactResolverOptions options)
    : options_(options)
{
}

LiteBackendArtifactResolverResult LiteBackendArtifactResolver::resolve(
    const LiteBackendArtifactResolverInput& input) const
{
    return evaluateLiteBackendArtifactResolver(input, options_);
}

LiteBackendActivationReadinessAdapter::LiteBackendActivationReadinessAdapter(
    LiteBackendActivationReadinessOptions options)
    : options_(options)
{
}

LiteBackendActivationReadinessResult LiteBackendActivationReadinessAdapter::evaluate(
    const LiteBackendActivationReadinessInput& input) const
{
    return evaluateLiteBackendActivationReadiness(input, options_);
}

} // namespace dragonx::wallet
