import fs from 'fs-extra';
import path from 'path';
import type { Logger } from './console-logger';
import type { PathUtils } from './path-utils';
import type { DomainGenerationOptions } from '../templates/domains';
import { getDomainFiles } from '../templates/domains';

export interface DomainFactoryDependencies {
  logger: Logger;
  pathUtils: PathUtils;
  generateDomainFiles: (domainName: string, options: DomainGenerationOptions) => Promise<void>;
}

export class DomainFactory {
  constructor(private dependencies: DomainFactoryDependencies) {}

  async createDomain(domainName: string, options: DomainGenerationOptions): Promise<void> {
    const { logger, pathUtils } = this.dependencies;
    
    // Domain name validation
    if (!this.validateDomainName(domainName)) {
      logger.error(`❌ Invalid domain name: "${domainName}"`);
      logger.error('💡 Domain names must be valid TypeScript identifiers:');
      logger.error('   - Start with a letter');
      logger.error('   - Contain only letters, numbers, and underscores');
      logger.error('   - No hyphens, spaces, or special characters');
      logger.error('📝 Examples: "user", "userProfile", "user_profile", "orderManagement"');
      return;
    }

    const domainPath = pathUtils.getDomainPath(domainName);
    const domainsBasePath = pathUtils.getDomainsPath();

    // Check if domain already exists
    if (await fs.pathExists(domainPath)) {
      logger.error(`Domain "${domainName}" already exists in ${domainPath}`);
      return;
    }

    try {
      // Create src/domains folder if it doesn't exist
      await fs.ensureDir(domainsBasePath);

      // Create domain structure
      logger.info(`Creating domain "${domainName}"...`);

      // Create all folders
      const folders = ['entities', 'ports', 'services', 'adapters', 'hooks'];
      if (options.withUi) folders.push('ui');

      for (const folder of folders) {
        await fs.ensureDir(path.join(domainPath, folder));
      }

      // Generate and write all files
      const files = getDomainFiles(domainName, options);
      for (const file of files) {
        await fs.writeFile(path.join(domainPath, file.path), file.content, 'utf8');
      }

      // Display summary
      logger.success(`Domain "${domainName}" created successfully!`);
      logger.info(`Location: ${domainPath}`);
      logger.info('Generated structure:');
      console.log(`├── entities/`);
      console.log(`├── ports/`);
      console.log(`├── services/`);
      console.log(`├── adapters/`);
      console.log(`├── hooks/`);
      if (options.withUi) console.log(`├── ui/`);
      console.log(`└── index.ts`);

      logger.info(`💡 You can now import the domain with: import { ... } from './src/domains/${domainName}'`);

    } catch (error) {
      logger.error(`Error creating domain: ${error instanceof Error ? error.message : 'Unknown error'}`);
      
      // Cleanup on error
      if (await fs.pathExists(domainPath)) {
        await fs.remove(domainPath);
        logger.info('Cleanup completed after error.');
      }
    }
  }

  private validateDomainName(domainName: string): boolean {
    // Allow only valid TypeScript identifiers (no hyphens)
    const validNameRegex = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
    return validNameRegex.test(domainName);
  }
} 