import { APIError, createResources, validateDatabaseName } from '@agentuity/server';
import { z } from 'zod';
import { getCommand } from '../../../command-prefix';
import { getCatalystAPIClient } from '../../../config';
import { addResourceEnvVars } from '../../../env-util';
import { ErrorCode } from '../../../errors';
import { isDryRunMode, outputDryRun } from '../../../explain';
import * as tui from '../../../tui';
import { createSubcommand as defineSubcommand } from '../../../types';

export const createSubcommand = defineSubcommand({
	name: 'create',
	aliases: ['new'],
	description: 'Create a new database resource',
	tags: ['mutating', 'creates-resource', 'slow', 'requires-auth', 'requires-deployment'],
	idempotent: false,
	requires: { auth: true, org: true, region: true },
	examples: [
		{ command: getCommand('cloud db create'), description: 'Create new database' },
		{ command: getCommand('cloud db new'), description: 'Run new command' },
		{ command: getCommand('cloud db create --name my-db'), description: 'Create new database' },
		{ command: getCommand('--dry-run cloud db create'), description: 'Create new database' },
	],
	schema: {
		options: z.object({
			name: z.string().optional().describe('Custom database name'),
			description: z.string().optional().describe('Optional database description'),
		}),
		response: z.object({
			success: z.boolean().describe('Whether creation succeeded'),
			name: z.string().describe('Created database name'),
		}),
	},

	async handler(ctx) {
		const { logger, opts, orgId, region, auth, options } = ctx;

		// Validate database name if provided
		if (opts.name) {
			const validation = validateDatabaseName(opts.name);
			if (!validation.valid) {
				tui.fatal(validation.error!, ErrorCode.INVALID_ARGUMENT);
			}
		}

		// Handle dry-run mode
		if (isDryRunMode(options)) {
			let message = opts.name
				? `Would create database with name: ${opts.name} in region: ${region}`
				: `Would create database in region: ${region}`;
			if (opts.description) {
				message += ` with description: "${opts.description}"`;
			}
			outputDryRun(message, options);
			if (!options.json) {
				tui.newline();
				tui.info('[DRY RUN] Database creation skipped');
			}
			return {
				success: false,
				name: opts.name || 'dry-run-db',
			};
		}

		const catalystClient = getCatalystAPIClient(logger, auth, region, undefined, ctx.config);

		try {
			const created = await tui.spinner({
				message: `Creating database in ${region}`,
				clearOnSuccess: true,
				callback: async () => {
					return await createResources(catalystClient, orgId, region!, [
						{ type: 'db', name: opts.name, description: opts.description },
					]);
				},
			});
			const resource = created[0];
			if (resource) {
				// Write environment variables to .env if running inside a project
				if (ctx.projectDir && resource.env && Object.keys(resource.env).length > 0) {
					await addResourceEnvVars(ctx.projectDir, resource.env);
					if (!options.json) {
						tui.info('Environment variables written to .env');
					}
				}

				if (!options.json) {
					tui.success(`Created database: ${tui.bold(resource.name)}`);
				}
				return {
					success: true,
					name: resource.name,
				};
			}
			tui.fatal('Failed to create database');
		} catch (ex) {
			if (ex instanceof APIError) {
				if (ex.status === 409) {
					const dbName = opts.name || 'auto-generated';
					tui.fatal(
						`database with the name "${dbName}" already exists. Use another name or don't specify --name for a unique name to be generated automatically.`,
						ErrorCode.INVALID_ARGUMENT
					);
				}
			}
			throw ex;
		}
	},
});
