/**
 * Init command
 * Initializes a new project with optional preset
 */

import * as path from 'path';
import * as fs from 'fs';
import inquirer from 'inquirer';
import { CommitManager } from '../../commit/commit-manager';
import * as output from '../output';

interface InitOptions {
  preset?: string;
  example: boolean;
}

const PRESETS: Record<string, PresetConfig> = {
  mern: {
    name: 'MERN Stack',
    description: 'MongoDB, Express, React, Node.js',
    stack: {
      frontend: {
        type: 'frontend',
        technology: 'react',
      },
      backend: {
        type: 'backend',
        technology: 'typescript/express',
      },
      database: {
        type: 'database',
        technology: 'mongodb',
      },
    },
  },
  'next-trpc': {
    name: 'Next.js + tRPC',
    description: 'Next.js with tRPC and Prisma',
    stack: {
      app: {
        type: 'frontend',
        technology: 'nextjs',
      },
      database: {
        type: 'database',
        technology: 'postgresql',
      },
    },
  },
  'django-react': {
    name: 'Django + React',
    description: 'Django REST framework with React frontend',
    stack: {
      frontend: {
        type: 'frontend',
        technology: 'react',
      },
      backend: {
        type: 'backend',
        technology: 'python/django',
      },
      database: {
        type: 'database',
        technology: 'postgresql',
      },
    },
  },
};

interface PresetConfig {
  name: string;
  description: string;
  stack: Record<string, any>;
}

export async function initCommand(projectName?: string, options: InitOptions = { example: false }) {
  const spinner = output.spinner('');

  try {
    // Show banner
    output.banner('Initialize New Project', 'Create a new Bangstack project with preset or custom configuration');

    // Interactive prompts
    const answers = await inquirer.prompt([
      {
        type: 'input',
        name: 'projectName',
        message: 'Project name:',
        default: projectName || 'my-app',
        when: !projectName,
        validate: (input: string) => {
          if (!input || input.trim().length === 0) {
            return 'Project name is required';
          }
          if (!/^[a-z0-9-]+$/.test(input)) {
            return 'Project name must contain only lowercase letters, numbers, and hyphens';
          }
          const projectPath = path.resolve(process.cwd(), input);
          if (fs.existsSync(projectPath)) {
            return `Directory already exists: ${input}`;
          }
          return true;
        },
      },
      {
        type: 'list',
        name: 'preset',
        message: 'Choose a preset:',
        when: !options.preset && !options.example,
        choices: [
          ...Object.entries(PRESETS).map(([key, preset]) => ({
            name: `${preset.name} - ${preset.description}`,
            value: key,
          })),
          { name: 'Example workflow (user authentication)', value: 'example' },
          { name: 'Start from scratch', value: 'custom' },
        ],
      },
      {
        type: 'list',
        name: 'frontend',
        message: 'Frontend technology:',
        when: (answers) => answers.preset === 'custom',
        choices: [
          { name: 'React', value: 'react' },
          { name: 'Next.js', value: 'nextjs' },
          { name: 'Vue', value: 'vue' },
          { name: 'None', value: null },
        ],
      },
      {
        type: 'list',
        name: 'backend',
        message: 'Backend technology:',
        when: (answers) => answers.preset === 'custom',
        choices: [
          { name: 'TypeScript/Express', value: 'typescript/express' },
          { name: 'Python/Django', value: 'python/django' },
          { name: 'Python/FastAPI', value: 'python/fastapi' },
          { name: 'Go/Gin', value: 'go/gin' },
          { name: 'None', value: null },
        ],
      },
      {
        type: 'list',
        name: 'database',
        message: 'Database:',
        when: (answers) => answers.preset === 'custom',
        choices: [
          { name: 'PostgreSQL', value: 'postgresql' },
          { name: 'MongoDB', value: 'mongodb' },
          { name: 'MySQL', value: 'mysql' },
          { name: 'None', value: null },
        ],
      },
      {
        type: 'confirm',
        name: 'docker',
        message: 'Include Docker configuration?',
        default: true,
        when: (answers) => answers.preset === 'custom',
      },
    ]);

    // Determine final project name and configuration
    const finalProjectName = projectName || answers.projectName;
    const projectPath = path.resolve(process.cwd(), finalProjectName);

    // Check if directory already exists (in case projectName was provided)
    if (fs.existsSync(projectPath)) {
      output.errorWithSuggestions(
        `Directory already exists: ${finalProjectName}`,
        [
          'Choose a different project name',
          'Delete the existing directory first',
        ]
      );
      process.exit(1);
    }

    // Determine which preset to use
    let selectedPreset = options.preset;
    let useExample = options.example;

    if (answers.preset) {
      if (answers.preset === 'example') {
        useExample = true;
      } else if (answers.preset === 'custom') {
        selectedPreset = undefined;
      } else {
        selectedPreset = answers.preset;
      }
    }

    output.blank();
    output.header('Creating Project');

    // Create project directory
    spinner.text = 'Creating project directory...';
    spinner.start();
    fs.mkdirSync(projectPath, { recursive: true });
    spinner.succeed('Created project directory');

    // Initialize .bangstack directory
    spinner.text = 'Initializing Bangstack...';
    spinner.start();
    const commitManager = new CommitManager(projectPath);
    commitManager.initialize();
    spinner.succeed('Initialized .bangstack directory');

    // Create workflows directory
    const workflowsPath = path.join(projectPath, 'workflows');
    fs.mkdirSync(workflowsPath, { recursive: true });

    // Create workflow file
    let workflowContent: string;

    if (selectedPreset && PRESETS[selectedPreset]) {
      const preset = PRESETS[selectedPreset];
      spinner.text = `Generating ${preset.name} workflow...`;
      spinner.start();

      workflowContent = generateWorkflowFromPreset(finalProjectName, preset);
    } else if (useExample) {
      spinner.text = 'Creating example workflow...';
      spinner.start();

      // Use the user-authentication example
      const examplePath = path.join(__dirname, '../../../examples/user-authentication.workflow.yaml');
      if (fs.existsSync(examplePath)) {
        workflowContent = fs.readFileSync(examplePath, 'utf-8');
      } else {
        workflowContent = generateBasicWorkflow(finalProjectName);
      }
    } else if (answers.preset === 'custom') {
      spinner.text = 'Generating custom workflow...';
      spinner.start();

      // Build custom stack from answers
      const customStack: Record<string, any> = {};

      if (answers.frontend) {
        customStack.frontend = {
          type: 'frontend',
          technology: answers.frontend,
        };
      }

      if (answers.backend) {
        customStack.backend = {
          type: 'backend',
          technology: answers.backend,
        };
      }

      if (answers.database) {
        customStack.database = {
          type: 'database',
          technology: answers.database,
        };
      }

      if (answers.docker && (answers.frontend || answers.backend)) {
        customStack.docker = {
          type: 'infrastructure',
          technology: 'docker',
        };
      }

      workflowContent = generateWorkflowFromPreset(finalProjectName, {
        name: 'Custom Stack',
        description: 'Custom configuration',
        stack: customStack,
      });
    } else {
      workflowContent = generateBasicWorkflow(finalProjectName);
    }

    const workflowFile = path.join(workflowsPath, `${finalProjectName}.workflow.yaml`);
    fs.writeFileSync(workflowFile, workflowContent);

    // Also save as config.yaml in .bangstack directory
    const configFile = path.join(projectPath, '.bangstack', 'config.yaml');
    fs.writeFileSync(configFile, workflowContent);

    spinner.succeed('Created workflow file');

    // Create README
    spinner.text = 'Creating README...';
    spinner.start();
    const readmeContent = generateReadme(finalProjectName, selectedPreset);
    fs.writeFileSync(path.join(projectPath, 'README.md'), readmeContent);
    spinner.succeed('Created README');

    // Create .gitignore
    const gitignoreContent = `node_modules/
dist/
generated/
.env
*.log
.DS_Store
.bangstack/cache/
`;
    fs.writeFileSync(path.join(projectPath, '.gitignore'), gitignoreContent);

    // Success summary
    output.blank();
    output.success('Project initialized successfully!');
    output.blank();

    // Show project info
    output.header('Project Summary');
    const stackComponents = Object.entries(
      selectedPreset && PRESETS[selectedPreset] ? PRESETS[selectedPreset].stack :
      answers.preset === 'custom' ? {
        ...(answers.frontend ? { frontend: answers.frontend } : {}),
        ...(answers.backend ? { backend: answers.backend } : {}),
        ...(answers.database ? { database: answers.database } : {}),
      } : {}
    );

    if (stackComponents.length > 0) {
      output.table([
        ['Project Name', output.bold(finalProjectName)],
        ['Location', output.path(projectPath)],
        ['Stack Components', stackComponents.map(([name]) => name).join(', ')],
      ]);
    } else {
      output.table([
        ['Project Name', output.bold(finalProjectName)],
        ['Location', output.path(projectPath)],
      ]);
    }

    // Next steps
    output.blank();
    output.header('Next Steps');
    output.list([
      `cd ${finalProjectName}`,
      `bang generate workflows/${finalProjectName}.workflow.yaml --output ./generated`,
      'Follow the generated README.md for more instructions',
    ], 'blue');
    output.blank();

  } catch (error) {
    spinner.fail('Initialization failed');

    output.blank();

    if (error instanceof Error) {
      output.error(error.message);
    } else {
      output.error(String(error));
    }

    output.blank();
    output.errorWithSuggestions(
      'Initialization failed',
      [
        'Check that you have write permissions in the current directory',
        'Ensure the project name is valid',
        'Try running with --verbose for more details',
      ]
    );

    process.exit(1);
  }
}

function generateWorkflowFromPreset(projectName: string, preset: PresetConfig): string {
  const workflowId = projectName.toLowerCase().replace(/[^a-z0-9-]/g, '-');

  return `# ${projectName} Workflow
# Generated with ${preset.name} preset

workflow:
  id: ${workflowId}
  version: 1.0.0
  name: ${projectName}
  description: ${preset.description}

stack:
${Object.entries(preset.stack)
  .map(([name, config]) => `  ${name}:
    type: ${config.type}
    technology: ${config.technology}`)
  .join('\n')}

# Add your documentation here
documentation:
  user_docs: []
  developer_docs: []
`;
}

function generateBasicWorkflow(projectName: string): string {
  const workflowId = projectName.toLowerCase().replace(/[^a-z0-9-]/g, '-');

  return `# ${projectName} Workflow

workflow:
  id: ${workflowId}
  version: 1.0.0
  name: ${projectName}
  description: A new Bangstack project

stack:
  # Define your stack components here
  # Example:
  # web-app:
  #   type: frontend
  #   technology: react
  #
  # api:
  #   type: backend
  #   technology: typescript/express
  #
  # database:
  #   type: database
  #   technology: postgresql

documentation:
  user_docs: []
  developer_docs: []
`;
}

function generateReadme(projectName: string, preset?: string): string {
  return `# ${projectName}

${preset ? `Generated with Bangstack using the **${PRESETS[preset]?.name}** preset.` : 'A Bangstack project.'}

## Getting Started

1. Edit your workflow file:
   \`\`\`bash
   workflows/${projectName}.workflow.yaml
   \`\`\`

2. Generate code:
   \`\`\`bash
   bang generate workflows/${projectName}.workflow.yaml --output ./generated
   \`\`\`

3. Navigate to generated components and install dependencies:
   \`\`\`bash
   cd generated/<component-name>
   npm install
   \`\`\`

## Documentation

- [Bangstack Documentation](https://github.com/mogullabs/bangstack)
- [Workflow Schema](https://github.com/mogullabs/bangstack/blob/main/docs/WORKFLOW-SCHEMA.md)

## License

MIT
`;
}
