import { deleteResources, listOrgResources } from '@agentuity/server';
import enquirer from 'enquirer';
import { z } from 'zod';
import { deleteResourceRegion, getResourceInfo, setResourceInfo } from '../../../cache';
import { getCommand } from '../../../command-prefix';
import { getCatalystAPIClient, getGlobalCatalystAPIClient } from '../../../config';
import { removeResourceEnvVars } from '../../../env-util';
import { ErrorCode } from '../../../errors';
import { isDryRunMode, outputDryRun } from '../../../explain';
import * as tui from '../../../tui';
import { createSubcommand } from '../../../types';
import { createS3Client } from './utils';
export const deleteSubcommand = createSubcommand({
    name: 'delete',
    aliases: ['rm', 'del', 'remove', 'terminate'],
    description: 'Delete a storage resource, file, or folder',
    tags: ['destructive', 'deletes-resource', 'slow', 'requires-auth', 'requires-deployment'],
    idempotent: false,
    requires: { auth: true },
    optional: { org: true },
    examples: [
        {
            command: getCommand('cloud storage delete my-bucket'),
            description: 'Delete a storage bucket',
        },
        {
            command: getCommand('cloud storage rm my-bucket file.txt'),
            description: 'Delete a file from a bucket',
        },
        {
            command: getCommand('cloud storage delete'),
            description: 'Interactive selection to delete a bucket',
        },
        {
            command: getCommand('cloud storage delete my-bucket path/to/folder'),
            description: 'Delete a folder and all its contents from a bucket',
        },
        {
            command: getCommand('--dry-run cloud storage delete my-bucket'),
            description: 'Dry-run: show what would be deleted without making changes',
        },
    ],
    schema: {
        args: z.object({
            name: z.string().optional().describe('Bucket name'),
            filename: z.string().optional().describe('File path to delete from bucket'),
        }),
        options: z.object({
            confirm: z.boolean().optional().describe('Skip confirmation prompts'),
        }),
        response: z.object({
            success: z.boolean().describe('Whether deletion succeeded'),
            name: z.string().describe('Deleted bucket or file name'),
            count: z.number().optional().describe('Number of files deleted (for folder deletion)'),
        }),
    },
    async handler(ctx) {
        const { logger, args, opts, auth, options, config } = ctx;
        const profileName = config?.name ?? 'production';
        const catalystClient = await getGlobalCatalystAPIClient(logger, auth, profileName, undefined, config);
        let bucketName = args.name;
        // If bucket name provided, try cache first for orgId
        let orgId = ctx.orgId;
        if (bucketName && !orgId) {
            const cachedInfo = await getResourceInfo('bucket', profileName, bucketName);
            orgId = cachedInfo?.orgId;
        }
        // For interactive selection (no bucket name), we need orgId
        if (!bucketName && !orgId) {
            tui.fatal('Organization required for interactive bucket selection. Specify --org-id or provide bucket name.', ErrorCode.INVALID_ARGUMENT);
        }
        // If we still don't have orgId and have a bucket name, error out
        if (!orgId) {
            tui.fatal(`Organization not found for bucket '${bucketName}'. Run 'agentuity cloud storage list' first or specify --org-id.`, ErrorCode.INVALID_ARGUMENT);
        }
        const resources = await tui.spinner({
            message: `Fetching storage for ${orgId}`,
            clearOnSuccess: true,
            callback: async () => {
                return listOrgResources(catalystClient, { type: 's3', orgId });
            },
        });
        // Cache all fetched buckets
        for (const s3 of resources.s3) {
            if (s3.cloud_region) {
                await setResourceInfo('bucket', profileName, s3.bucket_name, s3.cloud_region, orgId);
            }
        }
        if (!bucketName) {
            if (resources.s3.length === 0) {
                tui.info('No storage buckets found to delete');
                return { success: false, name: '' };
            }
            const response = await enquirer.prompt({
                type: 'select',
                name: 'bucket',
                message: 'Select storage bucket to delete:',
                choices: resources.s3.map((s3) => ({
                    name: s3.bucket_name,
                    message: s3.bucket_name,
                })),
            });
            bucketName = response.bucket;
        }
        // If filename is provided, delete the file or folder from the bucket
        if (args.filename) {
            const bucket = resources.s3.find((s3) => s3.bucket_name === bucketName);
            if (!bucket) {
                tui.fatal(`Storage bucket '${bucketName}' not found`, ErrorCode.RESOURCE_NOT_FOUND);
            }
            if (!bucket.access_key || !bucket.secret_key || !bucket.endpoint) {
                tui.fatal(`Storage bucket '${bucketName}' 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 filePath = args.filename;
            // Check if path represents a folder by listing objects under it
            const folderPrefix = filePath.endsWith('/') ? filePath : filePath + '/';
            const folderContents = [];
            let continuationToken;
            let isTruncated = false;
            do {
                const folderResult = await s3Client.list({
                    prefix: folderPrefix,
                    ...(continuationToken ? { continuationToken } : {}),
                });
                if (folderResult.contents) {
                    folderContents.push(...folderResult.contents);
                }
                continuationToken = folderResult.nextContinuationToken;
                isTruncated = folderResult.isTruncated ?? false;
            } while (isTruncated);
            if (folderContents.length > 0) {
                // Path is a folder — recursive delete
                const keysToDelete = folderContents.map((obj) => obj.key);
                // Handle dry-run mode
                if (isDryRunMode(options)) {
                    outputDryRun(`Would delete ${keysToDelete.length} file${keysToDelete.length === 1 ? '' : 's'} under ${folderPrefix} from bucket ${bucketName}`, options);
                    if (!options.json) {
                        tui.newline();
                        tui.info('[DRY RUN] Folder deletion skipped');
                    }
                    return { success: false, name: filePath, count: keysToDelete.length };
                }
                // Confirm
                if (!opts.confirm) {
                    tui.warning(`You are about to delete ${tui.bold(String(keysToDelete.length))} file${keysToDelete.length === 1 ? '' : 's'} under folder: ${tui.bold(folderPrefix)} from bucket: ${tui.bold(bucketName)}`);
                    const confirm = await enquirer.prompt({
                        type: 'confirm',
                        name: 'confirm',
                        message: 'Are you sure you want to delete this folder and all its contents?',
                        initial: false,
                    });
                    if (!confirm.confirm) {
                        tui.info('Deletion cancelled');
                        return { success: false, name: filePath };
                    }
                }
                // Delete all files
                await tui.spinner({
                    message: `Deleting ${keysToDelete.length} file${keysToDelete.length === 1 ? '' : 's'} under ${folderPrefix} from ${bucketName}`,
                    clearOnSuccess: true,
                    callback: async () => {
                        const errors = [];
                        for (const key of keysToDelete) {
                            try {
                                await s3Client.delete(key);
                            }
                            catch (err) {
                                errors.push({
                                    key,
                                    error: err instanceof Error ? err.message : String(err),
                                });
                            }
                        }
                        if (errors.length > 0) {
                            const failedKeys = errors.map((e) => e.key).join(', ');
                            throw new Error(`Failed to delete ${errors.length} file${errors.length === 1 ? '' : 's'}: ${failedKeys}`);
                        }
                    },
                });
                // Also delete the exact file if it exists (handles file+folder name conflicts)
                // Skip if filePath was already deleted as part of folder contents (e.g., trailing-slash folder markers)
                if (!keysToDelete.includes(filePath)) {
                    const exactFileCheck = await s3Client.list({ prefix: filePath });
                    const exactFile = (exactFileCheck.contents || []).find((obj) => obj.key === filePath);
                    if (exactFile) {
                        await s3Client.delete(filePath);
                        keysToDelete.push(filePath);
                    }
                }
                if (!options.json) {
                    tui.success(`Deleted ${tui.bold(String(keysToDelete.length))} file${keysToDelete.length === 1 ? '' : 's'} under ${tui.bold(folderPrefix)} from ${tui.bold(bucketName)}`);
                }
                return { success: true, name: filePath, count: keysToDelete.length };
            }
            // Not a folder — check if exact file exists
            const fileResult = await s3Client.list({ prefix: filePath });
            const exactMatch = (fileResult.contents || []).find((obj) => obj.key === filePath);
            if (!exactMatch) {
                tui.fatal(`No file or folder found at '${filePath}' in bucket '${bucketName}'`, ErrorCode.RESOURCE_NOT_FOUND);
            }
            // Handle dry-run mode
            if (isDryRunMode(options)) {
                outputDryRun(`Would delete file ${filePath} from bucket ${bucketName}`, options);
                if (!options.json) {
                    tui.newline();
                    tui.info('[DRY RUN] File deletion skipped');
                }
                return {
                    success: false,
                    name: filePath,
                };
            }
            if (!opts.confirm) {
                tui.warning(`You are about to delete file: ${tui.bold(filePath)} from bucket: ${tui.bold(bucketName)}`);
                const confirm = await enquirer.prompt({
                    type: 'confirm',
                    name: 'confirm',
                    message: 'Are you sure you want to delete this file?',
                    initial: false,
                });
                if (!confirm.confirm) {
                    tui.info('Deletion cancelled');
                    return { success: false, name: filePath };
                }
            }
            await tui.spinner({
                message: `Deleting ${filePath} from ${bucketName}`,
                clearOnSuccess: true,
                callback: async () => {
                    await s3Client.delete(filePath);
                },
            });
            if (!options.json) {
                tui.success(`Deleted file: ${tui.bold(filePath)} from ${tui.bold(bucketName)}`);
            }
            return {
                success: true,
                name: filePath,
            };
        }
        // Otherwise, delete the bucket
        // Find the bucket to get its region
        const bucketToDelete = resources.s3.find((s3) => s3.bucket_name === bucketName);
        if (!bucketToDelete) {
            tui.fatal(`Storage bucket '${bucketName}' not found`, ErrorCode.RESOURCE_NOT_FOUND);
        }
        if (!bucketToDelete.cloud_region) {
            tui.fatal(`Storage bucket '${bucketName}' is missing region information`, ErrorCode.RESOURCE_NOT_FOUND);
        }
        const region = bucketToDelete.cloud_region;
        // Handle dry-run mode
        if (isDryRunMode(options)) {
            outputDryRun(`Would delete storage bucket: ${bucketName} (region: ${region})`, options);
            if (!options.json) {
                tui.newline();
                tui.info('[DRY RUN] Storage bucket deletion skipped');
            }
            return {
                success: false,
                name: bucketName,
            };
        }
        if (!opts.confirm) {
            tui.warning(`You are about to delete storage bucket: ${tui.bold(bucketName)}`);
            const confirm = await enquirer.prompt({
                type: 'confirm',
                name: 'confirm',
                message: 'Are you sure you want to delete this storage bucket?',
                initial: false,
            });
            if (!confirm.confirm) {
                tui.info('Deletion cancelled');
                return { success: false, name: bucketName };
            }
        }
        // Use regional client for the delete operation
        const regionalClient = getCatalystAPIClient(logger, auth, region, undefined, config);
        const deleted = await tui.spinner({
            message: `Deleting storage bucket ${bucketName}`,
            clearOnSuccess: true,
            callback: async () => {
                return deleteResources(regionalClient, orgId, region, [
                    { type: 's3', name: bucketName },
                ]);
            },
        });
        const resource = deleted[0];
        if (resource) {
            // Clear cache entry for deleted bucket
            await deleteResourceRegion('bucket', profileName, resource.name);
            // Remove env vars from .env if running inside a project
            if (ctx.projectDir && resource.env_keys.length > 0) {
                await removeResourceEnvVars(ctx.projectDir, resource.env_keys);
                if (!options.json) {
                    tui.info(`Removed ${resource.env_keys.join(', ')} from .env`);
                }
            }
            if (!options.json) {
                tui.success(`Deleted storage bucket: ${tui.bold(resource.name)}`);
            }
            return {
                success: true,
                name: resource.name,
            };
        }
        tui.error('Failed to delete storage bucket');
        return { success: false, name: bucketName };
    },
});
//# sourceMappingURL=delete.js.map