#!/usr/bin/env bun

import { Command } from 'commander';
import fs from 'fs-extra';
import type { DomainGenerationOptions } from './templates/domains';
import {
  ConfigProvider,
  ConsoleLogger,
  DefaultPathUtils,
  DomainFactory,
} from './services';
import { createDomain } from './commands/create';
import { deleteDomain } from './commands/delete';
import { listDomains } from './commands/list';
import { createHttpClient } from './commands/http-client';
import { initServiceContext, generateServiceContext, updateServiceContext } from './commands/context';
import { initMsw, generateMswHandlers, generateMswMocks, updateMsw, updateMswDomain } from './commands/msw';
import { createVisualizeCommand } from './commands/visualize';
import { generateAiGuide } from './commands/guide-ai';
import { generateDomainFiles } from './templates/domains';

// Initialize services
const config = ConfigProvider.getConfig();
const logger = new ConsoleLogger();
const pathUtils = new DefaultPathUtils(config);
const domainFactory = new DomainFactory({
  logger,
  pathUtils,
  generateDomainFiles,
});

const program = new Command();

program
  .name('ruch')
  .description('Revolutionary React TypeScript CLI with hexagonal architecture & AI-powered development assistance')
  .version('1.1.3');

// Create command
program
  .command('create')
  .description('Create a new domain with its hexagonal structure')
  .argument('<domain>', 'Name of the domain to create')
  .option('--with-ui', 'Include UI folder with React components', true)
  .option('--without-ui', 'Exclude UI folder')
  .option('--with-store', 'Include store folder with Zustand', true)
  .option('--without-store', 'Exclude store folder')
  .option('--with-queries', 'Include queries folder with React Query', true)
  .option('--without-queries', 'Exclude queries folder')
  .option('--with-api', 'Include API folder with Axios', true)
  .option('--without-api', 'Exclude API folder')
  .action(async (domainName: string, options) => {
    try {
      const domainOptions: DomainGenerationOptions = {
        withUi: options.withoutUi ? false : options.withUi,
        withStore: options.withoutStore ? false : options.withStore,
        withQueries: options.withoutQueries ? false : options.withQueries,
        withApi: options.withoutApi ? false : options.withApi,
      };

      await domainFactory.createDomain(domainName, domainOptions);
    } catch (error) {
      logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
      process.exit(1);
    }
  });

// Delete command
program
  .command('delete')
  .description('Delete an existing domain')
  .argument('<domain>', 'Name of the domain to delete')
  .option('-f, --force', 'Force deletion without asking for confirmation', false)
  .action(async (domainName: string, options) => {
    try {
      await deleteDomain(domainName, options.force, fs, logger);
    } catch (error) {
      logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
      process.exit(1);
    }
  });

// List command
program
  .command('list')
  .description('List all existing domains')
  .action(async () => {
    try {
      await listDomains(fs, logger);
    } catch (error) {
      logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
      process.exit(1);
    }
  });

// Context command with subcommands
const contextCommand = program
  .command('context')
  .description('Manage React service context for dependency injection');

contextCommand
  .command('init')
  .description('Initialize empty service context')
  .action(async () => {
    try {
      await initServiceContext(fs, logger);
    } catch (error) {
      logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
      process.exit(1);
    }
  });

contextCommand
  .command('generate')
  .description('Generate service context with all existing domains')
  .action(async () => {
    try {
      await generateServiceContext(fs, logger);
    } catch (error) {
      logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
      process.exit(1);
    }
  });

contextCommand
  .command('update')
  .description('Update service context with missing domains')
  .action(async () => {
    try {
      await updateServiceContext(fs, logger);
    } catch (error) {
      logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
      process.exit(1);
    }
  });

// HTTP Client command
program
  .command('http-client')
  .description('Generate a default HTTP client configuration')
  .action(async () => {
    try {
      await createHttpClient(fs, logger);
    } catch (error) {
      logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
      process.exit(1);
    }
  });

// Guide AI command
program
  .command('guide-ai')
  .description('Generate AI-friendly documentation and configuration for the project architecture')
  .option('--tools <tools>', 'Integrate with specific AI tools (cursor, copilot, windsurf, juni)', '')
  .action(async (options: { tools?: string }) => {
    try {
      const tools = options.tools ? options.tools.split(',').map((t: string) => t.trim()) : [];
      await generateAiGuide(logger, tools);
    } catch (error) {
      logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
      process.exit(1);
    }
  });

// MSW command with subcommands
const mswCommand = program
  .command('msw')
  .description('Manage Mock Service Worker (MSW) configuration and handlers');

mswCommand
  .command('init')
  .description('Initialize MSW configuration in the project')
  .action(async () => {
    try {
      await initMsw(fs, logger);
    } catch (error) {
      logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
      process.exit(1);
    }
  });

mswCommand
  .command('handlers')
  .description('Generate MSW handlers for all domains')
  .action(async () => {
    try {
      await generateMswHandlers(fs, logger);
    } catch (error) {
      logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
      process.exit(1);
    }
  });

mswCommand
  .command('mocks')
  .description('Generate mock data for all domains')
  .action(async () => {
    try {
      await generateMswMocks(fs, logger);
    } catch (error) {
      logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
      process.exit(1);
    }
  });

mswCommand
  .command('update')
  .description('Update MSW configuration with missing handlers or for a specific domain')
  .argument('[domain]', 'Specific domain to update (optional)')
  .action(async (domain?: string) => {
    try {
      if (domain) {
        await updateMswDomain(domain, fs, logger);
      } else {
        await updateMsw(fs, logger);
      }
    } catch (error) {
      logger.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
      process.exit(1);
    }
  });

// Add visualize command
program.addCommand(createVisualizeCommand());

// Display help if no command is provided
if (process.argv.length <= 2) {
  program.help();
}

// Global error handling
process.on('uncaughtException', (error) => {
  logger.error(`Unhandled error: ${error.message}`);
  process.exit(1);
});

process.on('unhandledRejection', (reason) => {
  logger.error(`Unhandled rejection: ${reason}`);
  process.exit(1);
});

// Start the program
program.parse(); 