import { listOrgResources } from '@agentuity/server';
import { z } from 'zod';
import { 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';
const StorageListResponseSchema = z.object({
    buckets: z
        .array(z.object({
        bucket_name: z.string().describe('Storage bucket name'),
        access_key: z.string().optional().describe('S3 access key'),
        secret_key: z.string().optional().describe('S3 secret key'),
        region: z.string().optional().describe('S3 region'),
        endpoint: z.string().optional().describe('S3 endpoint URL'),
        cloud_region: z.string().optional().describe('Cloud region where bucket is hosted'),
        org_id: z.string().optional().describe('Organization ID that owns this bucket'),
        org_name: z.string().optional().describe('Organization name that owns this bucket'),
        bucket_type: z.string().optional().describe('Bucket type (user or snapshots)'),
        internal: z.boolean().optional().describe('Whether this is a system-managed bucket'),
        description: z.string().optional().describe('Optional description of the bucket'),
        object_count: z.number().int().optional().describe('Number of objects in this bucket'),
        total_size: z.number().int().optional().describe('Total size of objects in bytes'),
        last_event_at: z.string().optional().describe('Last activity timestamp'),
    }))
        .optional()
        .describe('List of storage resources'),
    files: z
        .array(z.object({
        key: z.string().describe('File key/path'),
        size: z.number().describe('File size in bytes'),
        lastModified: z.string().describe('Last modified timestamp'),
    }))
        .optional()
        .describe('List of files in bucket'),
});
export const listSubcommand = createSubcommand({
    name: 'list',
    aliases: ['ls'],
    description: 'List storage resources or files in a bucket',
    tags: ['read-only', 'fast', 'requires-auth'],
    requires: { auth: true },
    idempotent: true,
    examples: [
        { command: getCommand('cloud storage list'), description: 'List items' },
        { command: getCommand('cloud storage list my-bucket'), description: 'List items' },
        {
            command: getCommand('cloud storage list my-bucket path/prefix'),
            description: 'List items',
        },
        {
            command: getCommand('--json cloud storage list'),
            description: 'Show output in JSON format',
        },
        { command: getCommand('cloud storage ls'), description: 'List items' },
        {
            command: getCommand('cloud storage list --show-credentials'),
            description: 'Use show credentials option',
        },
    ],
    schema: {
        args: z.object({
            name: z.string().optional().describe('Bucket name to list files from'),
            prefix: z.string().optional().describe('Path prefix to filter files'),
        }),
        options: z.object({
            orgId: z.string().optional().describe('filter by organization id'),
            name: z.string().optional().describe('Filter by bucket name'),
            showCredentials: z
                .boolean()
                .optional()
                .describe('Show credentials in plain text (default: masked in terminal, unmasked in JSON)'),
            nameOnly: z.boolean().optional().describe('Print the name only'),
            sort: z
                .enum(['name', 'created', 'region'])
                .default('created')
                .describe('field to sort by'),
            direction: z.enum(['asc', 'desc']).default('desc').describe('sort direction'),
            limit: z.coerce.number().min(0).optional().describe('Maximum number of results to return'),
            offset: z.coerce.number().min(0).optional().describe('Offset for pagination'),
        }),
        response: StorageListResponseSchema,
    },
    webUrl: (ctx) => ctx.args.name
        ? `/services/storage/${encodeURIComponent(ctx.args.name)}`
        : '/services/storage',
    async handler(ctx) {
        const { logger, args, opts, options, auth, config } = ctx;
        const catalystClient = await getGlobalCatalystAPIClient(logger, auth, config?.name, undefined, config);
        const profileName = config?.name ?? 'production';
        const resources = await tui.spinner({
            message: 'Fetching storage',
            clearOnSuccess: true,
            callback: async () => {
                return listOrgResources(catalystClient, {
                    type: 's3',
                    orgId: opts?.orgId,
                    ...(args.name
                        ? { name: args.name }
                        : {
                            name: opts?.name,
                            sort: opts?.sort,
                            direction: opts?.direction,
                            limit: opts?.limit,
                            offset: opts?.offset,
                        }),
                });
            },
        });
        // Cache each bucket with its region and orgId for future lookups
        for (const s3 of resources.s3) {
            if (s3.cloud_region && s3.org_id) {
                await setResourceInfo('bucket', profileName, s3.bucket_name, s3.cloud_region, s3.org_id);
            }
        }
        // If bucket name is provided, list files in the bucket
        if (args.name) {
            const bucket = resources.s3.find((s3) => s3.bucket_name === args.name);
            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);
            }
            const s3Client = createS3Client({
                endpoint: bucket.endpoint,
                access_key: bucket.access_key,
                secret_key: bucket.secret_key,
                region: bucket.region,
            });
            const result = await tui.spinner({
                message: `Listing files in ${args.name}${args.prefix ? ` with prefix ${args.prefix}` : ''}`,
                clearOnSuccess: true,
                callback: async () => {
                    return s3Client.list(args.prefix
                        ? {
                            prefix: args.prefix,
                        }
                        : null);
                },
            });
            const objects = result.contents || [];
            if (!options.json) {
                if (objects.length === 0) {
                    tui.info('No files found');
                }
                else {
                    if (opts.nameOnly) {
                        for (const obj of objects) {
                            console.log(obj.key);
                        }
                    }
                    else {
                        tui.info(tui.bold(`Files in ${args.name}${args.prefix ? ` (prefix: ${args.prefix})` : ''}`));
                        tui.newline();
                        for (const obj of objects) {
                            console.log(`${obj.key}  ${tui.muted(`(${obj.size} bytes, ${obj.lastModified})`)}`);
                        }
                    }
                }
            }
            return {
                files: objects.map((obj) => {
                    const lastModified = obj.lastModified;
                    let lastModifiedStr = '';
                    if (typeof lastModified === 'string') {
                        lastModifiedStr = lastModified;
                    }
                    else if (lastModified &&
                        typeof lastModified === 'object' &&
                        'toISOString' in lastModified) {
                        lastModifiedStr = lastModified.toISOString();
                    }
                    return {
                        key: obj.key,
                        size: obj.size ?? 0,
                        lastModified: lastModifiedStr,
                    };
                }),
            };
        }
        // Otherwise, list buckets
        // Mask credentials in terminal output by default, unless --show-credentials is passed
        const shouldShowCredentials = opts.showCredentials === true;
        const shouldMask = !options.json && !shouldShowCredentials;
        // Check if resources span multiple orgs
        const uniqueOrgIds = new Set(resources.s3.map((s3) => s3.org_id));
        const showOrgColumn = uniqueOrgIds.size > 1;
        if (!options.json) {
            if (resources.s3.length === 0) {
                tui.info('No storage buckets found');
            }
            else {
                if (!opts.nameOnly) {
                    tui.info(tui.bold('Storage'));
                    tui.newline();
                }
                for (const s3 of resources.s3) {
                    if (opts.nameOnly) {
                        console.log(s3.bucket_name);
                        continue;
                    }
                    console.log(tui.bold(s3.bucket_name));
                    if (showOrgColumn) {
                        console.log(` Organization: ${tui.muted(s3.org_name || s3.org_id)}`);
                    }
                    if (s3.access_key) {
                        const displayAccessKey = shouldMask
                            ? tui.maskSecret(s3.access_key)
                            : s3.access_key;
                        console.log(` Access Key: ${tui.muted(displayAccessKey)}`);
                    }
                    if (s3.secret_key) {
                        const displaySecretKey = shouldMask
                            ? tui.maskSecret(s3.secret_key)
                            : s3.secret_key;
                        console.log(` Secret Key: ${tui.muted(displaySecretKey)}`);
                    }
                    if (s3.region)
                        console.log(` Region:     ${tui.muted(s3.region)}`);
                    if (s3.endpoint)
                        console.log(` Endpoint:   ${tui.muted(s3.endpoint)}`);
                    if (s3.object_count != null) {
                        const sizeStr = s3.total_size != null ? tui.formatBytes(s3.total_size) : 'unknown';
                        console.log(` Objects:    ${tui.muted(`${s3.object_count.toLocaleString()} (${sizeStr})`)}`);
                    }
                    if (s3.last_event_at) {
                        const date = new Date(s3.last_event_at);
                        if (Number.isNaN(date.getTime())) {
                            console.log(` Activity:   ${tui.muted('unknown')}`);
                        }
                        else {
                            console.log(` Activity:   ${tui.muted(date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric', hour: '2-digit', minute: '2-digit' }))}`);
                        }
                    }
                    tui.newline();
                }
            }
        }
        return {
            buckets: resources.s3.map((s3) => ({
                bucket_name: s3.bucket_name,
                access_key: s3.access_key ?? undefined,
                secret_key: s3.secret_key ?? undefined,
                region: s3.region ?? undefined,
                endpoint: s3.endpoint ?? undefined,
                cloud_region: s3.cloud_region,
                org_id: s3.org_id,
                org_name: s3.org_name,
                bucket_type: s3.bucket_type,
                internal: s3.internal,
                description: s3.description ?? undefined,
                object_count: s3.object_count ?? undefined,
                total_size: s3.total_size ?? undefined,
                last_event_at: s3.last_event_at ?? undefined,
            })),
        };
    },
});
//# sourceMappingURL=list.js.map