import { listOrgResources } from '@agentuity/server';
import { z } from 'zod';
import { getResourceInfo, setResourceInfo } from '../../../cache';
import { getCommand } from '../../../command-prefix';
import { getGlobalCatalystAPIClient } from '../../../config';
import { ErrorCode } from '../../../errors';
import * as tui from '../../../tui';
import { createSubcommand } from '../../../types';
import { createS3Client } from './utils';
export const downloadSubcommand = createSubcommand({
    name: 'download',
    description: 'Download a file from storage bucket',
    tags: ['read-only', 'requires-auth'],
    requires: { auth: true },
    optional: { org: true },
    idempotent: true,
    examples: [
        {
            command: `${getCommand('cloud storage download')} my-bucket file.txt`,
            description: 'Download file from bucket',
        },
        {
            command: `${getCommand('cloud storage download')} my-bucket file.txt output.txt`,
            description: 'Download file to specific path',
        },
        {
            command: `${getCommand('cloud storage download')} my-bucket file.txt - > output.txt`,
            description: 'Download file to stdout',
        },
        {
            command: `${getCommand('cloud storage download')} my-bucket file.txt --metadata`,
            description: 'Download metadata only',
        },
    ],
    schema: {
        args: z.object({
            name: z.string().describe('Bucket name'),
            filename: z.string().describe('File path to download'),
            output: z.string().optional().describe('Output file path or "-" for STDOUT'),
        }),
        options: z.object({
            metadata: z.boolean().optional().describe('Download metadata only (not file contents)'),
        }),
        response: z.object({
            success: z.boolean().describe('Whether download succeeded'),
            bucket: z.string().describe('Bucket name'),
            filename: z.string().describe('Downloaded filename'),
            size: z.number().optional().describe('File size in bytes'),
            contentType: z.string().optional().describe('Content type'),
            lastModified: z.string().optional().describe('Last modified timestamp'),
        }),
    },
    async handler(ctx) {
        const { logger, args, opts, options, auth, config } = ctx;
        const profileName = config?.name ?? 'production';
        const catalystClient = await getGlobalCatalystAPIClient(logger, auth, profileName, undefined, config);
        // Check cache first for orgId
        const cachedInfo = await getResourceInfo('bucket', profileName, args.name);
        const orgId = ctx.orgId ?? cachedInfo?.orgId;
        if (!orgId) {
            tui.fatal(`Organization not found for bucket '${args.name}'. Run 'agentuity cloud storage list' first or specify --org-id.`, ErrorCode.INVALID_ARGUMENT);
        }
        // Fetch bucket credentials
        const resources = await tui.spinner({
            message: `Fetching credentials for ${args.name}`,
            clearOnSuccess: true,
            callback: async () => {
                return listOrgResources(catalystClient, { type: 's3', orgId });
            },
        });
        const bucket = resources.s3.find((s3) => s3.bucket_name === args.name);
        // Cache the bucket info for future lookups
        if (bucket?.cloud_region) {
            await setResourceInfo('bucket', profileName, bucket.bucket_name, bucket.cloud_region, orgId);
        }
        if (!bucket) {
            tui.fatal(`Storage bucket '${args.name}' not found`, ErrorCode.RESOURCE_NOT_FOUND);
        }
        if (!bucket.access_key || !bucket.secret_key || !bucket.endpoint) {
            tui.fatal(`Storage bucket '${args.name}' is missing credentials`, ErrorCode.CONFIG_INVALID);
        }
        // Initialize S3 client
        const s3Client = createS3Client({
            endpoint: bucket.endpoint,
            access_key: bucket.access_key,
            secret_key: bucket.secret_key,
            region: bucket.region,
        });
        if (opts.metadata) {
            // Download metadata only
            const metadata = await tui.spinner({
                message: `Fetching metadata for ${args.filename}`,
                clearOnSuccess: true,
                callback: async () => {
                    return s3Client.stat(args.filename);
                },
            });
            if (!options.json) {
                console.log(tui.bold('File:          ') + args.filename);
                console.log(tui.bold('Bucket:        ') + args.name);
                if (metadata.size) {
                    console.log(tui.bold('Size:          ') + metadata.size + ' bytes');
                }
                if (metadata.type) {
                    console.log(tui.bold('Content Type:  ') + metadata.type);
                }
                if (metadata.lastModified) {
                    console.log(tui.bold('Last Modified: ') + metadata.lastModified);
                }
            }
            return {
                success: true,
                bucket: args.name,
                filename: args.filename,
                size: metadata.size,
                contentType: metadata.type,
                lastModified: metadata.lastModified?.toISOString(),
            };
        }
        // Download file content
        const s3File = s3Client.file(args.filename);
        const fileContent = await tui.spinner({
            message: `Downloading ${args.filename} from ${args.name}`,
            clearOnSuccess: true,
            callback: async () => {
                return Buffer.from(await s3File.arrayBuffer());
            },
        });
        // Write to output or STDOUT
        const outputPath = args.output || '-';
        if (outputPath === '-') {
            // Write to STDOUT
            // When outputting to STDOUT in JSON mode, we can't mix file content with JSON
            if (options.json) {
                tui.fatal('Cannot use --json with STDOUT output. Use --metadata to get JSON metadata, or specify an output file.', ErrorCode.INVALID_ARGUMENT);
            }
            process.stdout.write(fileContent);
        }
        else {
            // Write to file
            await Bun.write(outputPath, fileContent);
            if (!options.json) {
                tui.success(`Downloaded ${tui.bold(args.filename)} to ${tui.bold(outputPath)} (${fileContent.length} bytes)`);
            }
        }
        return {
            success: true,
            bucket: args.name,
            filename: args.filename,
            size: fileContent.length,
            contentType: s3File.type,
            lastModified: undefined,
        };
    },
});
//# sourceMappingURL=download.js.map