"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.browseVersions = browseVersions;
const commandContext_1 = require("../commandContext");
const errors_1 = require("../errors");
const messages_1 = require("../messages");
const output_1 = require("../output");
const refs_1 = require("../refs");
const appUrls_1 = require("../appUrls");
function formatCreatorReviewState(reviewState) {
    if (reviewState === 'FAILED') {
        return 'Blocked';
    }
    if (reviewState === 'LOW_QUALITY') {
        return 'Limited';
    }
    if (reviewState === 'PASSED') {
        return 'Passed';
    }
    if (reviewState === 'GOOD') {
        return 'Good';
    }
    if (reviewState === 'EXCELLENT') {
        return 'Excellent';
    }
    if (reviewState === 'RUNNING') {
        return 'In Review';
    }
    if (reviewState === 'QUEUED') {
        return 'Queued';
    }
    if (reviewState === 'SUPERSEDED') {
        return 'Superseded';
    }
    if (reviewState === 'ERROR') {
        return 'Review Error';
    }
    return 'Not Required';
}
function parsePositiveInteger(raw, label, fallback) {
    if (raw === undefined) {
        return fallback;
    }
    const parsed = typeof raw === 'number' ? raw : Number.parseInt(String(raw), 10);
    if (!Number.isInteger(parsed) || parsed < 0) {
        return null;
    }
    if (label === 'limit' && parsed <= 0) {
        return null;
    }
    return parsed;
}
function buildAssetSourceUrl(apiBase, ref, revision) {
    return `${apiBase}/assets/${encodeURIComponent(ref.creator)}/${encodeURIComponent(ref.name)}/versions/${revision}/source`;
}
function resolveAppSourceUrl(apiBase, sourceUrl) {
    const trimmed = typeof sourceUrl === 'string' ? sourceUrl.trim() : '';
    if (!trimmed) {
        return null;
    }
    return new URL(trimmed, apiBase).toString();
}
function buildAssetPackSourceUrl(apiBase, ref, version) {
    return `${apiBase}/asset-packs/${encodeURIComponent(ref.creator)}/${encodeURIComponent(ref.name)}/versions/${encodeURIComponent(version)}/source`;
}
function buildAssetPackDownloadUrl(apiBase, ref, version) {
    return `${apiBase}/asset-packs/${encodeURIComponent(ref.creator)}/${encodeURIComponent(ref.name)}/versions/${encodeURIComponent(version)}/download`;
}
function assetFileUrls(version) {
    const files = version.fileManifest?.files;
    if (!Array.isArray(files)) {
        return [];
    }
    return files
        .filter((entry) => typeof entry?.role === 'string' && typeof entry?.url === 'string' && entry.url.trim().length > 0)
        .map((entry) => ({ role: entry.role, url: entry.url.trim() }));
}
function printEntry(entry) {
    if (entry.kind === 'app') {
        const currentLabel = entry.isCurrent ? ' | current' : '';
        console.log(`${entry.version} | ${entry.visibility.toLowerCase()}${currentLabel} | ${formatCreatorReviewState(entry.reviewState)} | ${(0, output_1.formatTimestamp)(entry.createdAt)}`);
        console.log(`  Play URL: ${(0, output_1.formatOptionalValue)(entry.urls.play)}`);
        console.log(`  Source URL: ${(0, output_1.formatOptionalValue)(entry.urls.source)}`);
        if (entry.showCreatorFeedback && typeof entry.creatorFeedback === 'string' && entry.creatorFeedback.trim().length > 0) {
            console.log('  Creator Feedback:');
            for (const line of entry.creatorFeedback.split(/\r?\n/)) {
                console.log(`    ${line}`);
            }
        }
        return;
    }
    if (entry.kind === 'asset') {
        const currentLabel = entry.isCurrent ? ' | current' : '';
        console.log(`${entry.revisionLabel} | ${entry.visibility.toLowerCase()}${currentLabel} | ${entry.format.toLowerCase()} | ${entry.subcategory} | ${(0, output_1.formatTimestamp)(entry.createdAt)}`);
        console.log(`  Source URL: ${entry.urls.source}`);
        if (entry.urls.files.length > 0) {
            for (const file of entry.urls.files) {
                console.log(`  File URL (${file.role}): ${file.url}`);
            }
        }
        return;
    }
    if (entry.kind === 'asset-spec') {
        const currentLabel = entry.isCurrent ? ' | current' : '';
        console.log(`${entry.version} | ${entry.visibility.toLowerCase()} | ${entry.status.toLowerCase()}${currentLabel} | ${(0, output_1.formatTimestamp)(entry.createdAt)}`);
        console.log(`  Documentation URL: ${(0, output_1.formatOptionalValue)(entry.documentationUrl)}`);
        return;
    }
    const currentLabel = entry.isCurrent ? ' | current' : '';
    console.log(`${entry.version} | ${entry.visibility.toLowerCase()}${currentLabel} | ${(0, output_1.formatTimestamp)(entry.createdAt)}`);
    console.log(`  Download URL: ${(0, output_1.formatOptionalValue)(entry.urls.download)}`);
    console.log(`  Source URL: ${entry.urls.source}`);
}
async function loadVersionEntries(input) {
    const { client, envConfig, ref, limit, offset } = input;
    if (ref.kind === 'app') {
        const [appDetail, response] = await Promise.all([
            client.fetchAppBySlug(ref.creator, ref.name),
            client.listAppVersions(ref.creator, ref.name),
        ]);
        const listed = response.versions ?? [];
        const selected = listed.slice(offset, offset + limit);
        const normalizedAccountUsername = typeof input.accountUsername === 'string' ? input.accountUsername.trim() : '';
        const showCreatorFeedback = normalizedAccountUsername.length > 0 && normalizedAccountUsername === ref.creator;
        const entries = await Promise.all(selected.map(async (version) => {
            const detail = await client.getAppVersion(ref.creator, ref.name, version.version);
            return {
                kind: 'app',
                version: version.version,
                visibility: version.visibility,
                reviewState: detail.version.reviewState,
                creatorFeedback: detail.version.creatorFeedback ?? null,
                showCreatorFeedback,
                createdAt: version.createdAt,
                updatedAt: detail.version.updatedAt,
                releaseNotes: version.releaseNotes ?? null,
                isCurrent: Boolean(version.isCurrent),
                urls: {
                    play: (0, appUrls_1.buildPlatformPlayUrl)(envConfig.webBase, {
                        creatorUsername: ref.creator,
                        appName: ref.name,
                        appType: appDetail.app.type,
                    }),
                    source: resolveAppSourceUrl(envConfig.apiBase, detail.version.sourceUrl),
                },
            };
        }));
        return {
            entries,
            pagination: {
                limit,
                offset,
                count: entries.length,
                hasMore: listed.length > offset + limit,
            },
        };
    }
    if (ref.kind === 'asset') {
        const [detail, response] = await Promise.all([
            client.fetchAssetBySlug(ref.creator, ref.name),
            client.listAssetVersions(ref.creator, ref.name, { limit, offset }),
        ]);
        const currentRevision = detail.asset.currentVersion?.revision ?? null;
        return {
            entries: (response.versions ?? []).map((version) => ({
                kind: 'asset',
                revision: version.revision,
                revisionLabel: version.revisionLabel,
                visibility: version.visibility,
                createdAt: version.createdAt,
                updatedAt: version.updatedAt,
                subcategory: version.subcategory,
                format: version.format,
                isCurrent: currentRevision === version.revision,
                urls: {
                    source: buildAssetSourceUrl(envConfig.apiBase, ref, version.revision),
                    files: assetFileUrls(version),
                },
            })),
            pagination: response.pagination ?? {
                limit,
                offset,
                count: (response.versions ?? []).length,
                hasMore: false,
            },
        };
    }
    if (ref.kind === 'asset-pack') {
        const [detail, response] = await Promise.all([
            client.fetchAssetPackBySlug(ref.creator, ref.name),
            client.listAssetPackVersions(ref.creator, ref.name, { limit, offset }),
        ]);
        const currentVersion = detail.pack.currentVersion?.version ?? null;
        return {
            entries: (response.versions ?? []).map((version) => ({
                kind: 'asset-pack',
                version: version.version,
                visibility: version.visibility,
                createdAt: version.createdAt,
                updatedAt: version.updatedAt,
                isCurrent: currentVersion === version.version,
                urls: {
                    download: buildAssetPackDownloadUrl(envConfig.apiBase, ref, version.version),
                    source: buildAssetPackSourceUrl(envConfig.apiBase, ref, version.version),
                },
            })),
            pagination: response.pagination ?? {
                limit,
                offset,
                count: (response.versions ?? []).length,
                hasMore: false,
            },
        };
    }
    const [detail, response] = await Promise.all([
        client.fetchAssetSpecBySlug(ref.creator, ref.name),
        client.listAssetSpecVersions(ref.creator, ref.name, { limit, offset }),
    ]);
    const currentVersion = detail.assetSpec.currentVersion?.version ?? null;
    return {
        entries: (response.versions ?? []).map((version) => ({
            kind: 'asset-spec',
            version: version.version,
            visibility: version.visibility,
            status: version.status,
            createdAt: version.createdAt,
            updatedAt: version.updatedAt,
            isCurrent: currentVersion === version.version,
            documentationUrl: version.documentationUrl ?? null,
        })),
        pagination: response.pagination ?? {
            limit,
            offset,
            count: (response.versions ?? []).length,
            hasMore: false,
        },
    };
}
async function browseVersions(rawRef, options = {}) {
    let ref;
    try {
        ref = (0, refs_1.parseContentRef)(rawRef ?? '');
    }
    catch {
        (0, messages_1.printErrorWithHelp)('A canonical ref is required.', ['Use the format <creator>/<kind>/<name>.', 'Example: playdrop versions browse playdrop/app/hangingout', 'Example: playdrop versions browse playdrop/asset-spec/platformer-level'], { command: 'versions browse' });
        process.exitCode = 1;
        return;
    }
    const limit = parsePositiveInteger(options.limit, 'limit', 10);
    if (limit === null) {
        (0, messages_1.printErrorWithHelp)('The --limit value must be a positive integer.', ['Example: --limit 10'], { command: 'versions browse' });
        process.exitCode = 1;
        return;
    }
    const offset = parsePositiveInteger(options.offset, 'offset', 0);
    if (offset === null) {
        (0, messages_1.printErrorWithHelp)('The --offset value must be zero or a positive integer.', ['Example: --offset 20'], { command: 'versions browse' });
        process.exitCode = 1;
        return;
    }
    await (0, commandContext_1.withPublicEnvironment)('versions browse', async ({ client, envConfig, account }) => {
        try {
            const { entries, pagination } = await loadVersionEntries({
                client,
                envConfig,
                accountUsername: account?.username ?? null,
                ref,
                limit,
                offset,
            });
            if (options.json) {
                (0, output_1.printJson)({
                    kind: ref.kind,
                    ref: ref.ref,
                    entries: entries.map((entry) => {
                        if (entry.kind !== 'app') {
                            return entry;
                        }
                        const { showCreatorFeedback: _showCreatorFeedback, ...appEntry } = entry;
                        return appEntry;
                    }),
                    pagination,
                });
                return;
            }
            if (entries.length === 0) {
                console.log(`No versions found for "${ref.ref}".`);
                console.log('Next: run "playdrop detail ' + ref.ref + '" to inspect the current item state.');
                return;
            }
            console.log(`Versions for ${ref.ref}:\n`);
            for (const entry of entries) {
                printEntry(entry);
            }
            console.log('\nNext: use the URLs above directly, or run "playdrop detail ' + ref.ref + '" for the current item summary.');
        }
        catch (error) {
            const handled = (0, errors_1.handleCommandFailure)(error, 'versions browse', 'Version lookup', {
                apiMessage: (apiError) => {
                    if (apiError.status === 404) {
                        return {
                            problem: `No item was found for "${ref.ref}".`,
                            suggestions: ['Check the ref and retry.', 'Run "playdrop browse" to explore available content.'],
                        };
                    }
                    if (apiError.status === 401 || apiError.status === 403) {
                        return {
                            problem: `You do not have access to version history for "${ref.ref}".`,
                            suggestions: ['Run "playdrop auth login" if this is private content you own.'],
                        };
                    }
                    return {
                        problem: `Version lookup failed with status ${apiError.status}.`,
                        suggestions: ['Retry in a moment.', 'Use "playdrop help versions browse" for usage details.'],
                    };
                },
            });
            if (!handled) {
                throw error;
            }
        }
    });
}
