import fs from 'fs-extra';
import path from 'path';
import { buildDomainDirectoryPath, getDomainsSourceDirectoryPath, validateDomainName } from '../utils/paths';
import type { DomainGenerationOptions } from '../templates/domains';
import { getDomainFiles } from '../templates/domains';
import type { FileSystem } from '../utils/file-operations';
import {
  validateFileExists,
  createDirectory,
  writeFile,
  removeFile
} from '../utils/file-operations';
import type { Logger } from '../utils/logging';
import {
  logError,
  logSuccess,
  logInfo,
  logDomainAlreadyExists,
  logInvalidDomainName
} from '../utils/logging';

// Pure function to get required domain folders
const getRequiredDomainFolders = (options: DomainGenerationOptions): string[] => {
  const requiredFolders = [
    'entities',
    'ports',
    'services',
    'adapters',
    'hooks'
  ];
  if (options.withUi) requiredFolders.push('ui');
  return requiredFolders;
};

export const createDomain = async (
  domainName: string,
  options: DomainGenerationOptions,
  fileSystem: FileSystem = fs,
  log: Logger = require('../utils/logger').logger
) => {
  // Validation du nom
  if (!validateDomainName(domainName)) {
    logInvalidDomainName(log, domainName);
    return;
  }

  const domainPath = buildDomainDirectoryPath(domainName);
  const domainsSourcePath = getDomainsSourceDirectoryPath();

  // Vérification de l'existence du domaine
  if (await fileSystem.exists(domainPath)) {
    logDomainAlreadyExists(log, domainName, domainPath);
    return;
  }

  try {
    // Création du dossier src
    await fileSystem.ensureDir(path.join(process.cwd(), 'src'));

    // Création du dossier src/domains si besoin
    await fileSystem.ensureDir(domainsSourcePath);

    logInfo(log, `Creating domain "${domainName}"...`);

    // Création du dossier du domaine
    await fileSystem.ensureDir(domainPath);

    // Création des dossiers
    const requiredFolders = getRequiredDomainFolders(options);
    for (const folder of requiredFolders) {
      await fileSystem.ensureDir(path.join(domainPath, folder));
    }

    // Génération des fichiers
    const domainFiles = getDomainFiles(domainName, options);
    for (const file of domainFiles) {
      const filePath = path.join(domainPath, file.path);
      const dir = path.dirname(filePath);
      await fileSystem.ensureDir(dir);
      await fileSystem.writeFile(filePath, file.content, 'utf8');
    }

    // Affichage du résumé
    logSuccess(log, `Domain "${domainName}" created successfully!`);
    logInfo(log, `Location: ${domainPath}`);
    logInfo(log, 'Generated structure:');
    log.log(`├── entities/`);
    log.log(`├── ports/`);
    log.log(`├── services/`);
    log.log(`├── adapters/`);
    log.log(`├── hooks/`);
    if (options.withUi) log.log(`├── ui/`);
    logInfo(log, `💡 You can now import the domain with: import { ... } from './src/domains/${domainName}'`);
  } catch (error) {
    logError(log, `Error creating domain: ${error instanceof Error ? error.message : 'Unknown error'}`);
    // Nettoyage en cas d'erreur
    if (await fileSystem.exists(domainPath)) {
      await fileSystem.remove(domainPath);
      logInfo(log, 'Cleanup completed after error.');
    }
  }
}; 