/**
 * execute.ts — Execution logic. Imports from ../lib/. NO validation.
 * Receives validated data, returns typed result.
 */
import { join } from 'path';
import { existsSync, mkdirSync, writeFileSync } from 'fs';
import type { InitSpec, InitResult } from './types.js';
import { detectPlatform } from '../lib/platform.js';
import { detectProvider, parseAzureDevOpsUrl } from '../lib/provider.js';
import { execGit } from '../lib/git.js';
import { listWorktrees } from '../lib/worktree.js';
import { detectVersion } from '../lib/version.js';
import { normalizeForStorage } from '../lib/paths.js';

export async function execute(spec: InitSpec, workDir: string = process.cwd()): Promise<InitResult> {
  try {
    // Detect platform
    const platformInfo = detectPlatform();

    // If no URL provided, detect from current repo or ask for input
    let repoUrl = spec.url;
    let repoName = spec.name;

    if (!repoUrl) {
      // Try to detect from current git remote
      const remoteResult = await execGit(['config', '--get', 'remote.origin.url'], workDir);
      if (remoteResult.exitCode === 0 && remoteResult.stdout) {
        repoUrl = remoteResult.stdout;
      }
    }

    if (!repoUrl || !repoName) {
      // Need user input
      return {
        success: true,
        needsInput: true,
        detected: {
          platform: platformInfo.platform,
          provider: repoUrl ? detectProvider(repoUrl) : 'unknown',
        },
      };
    }

    // Detect provider and extract details
    const provider = detectProvider(repoUrl);
    const azureInfo = provider === 'azuredevops' ? parseAzureDevOpsUrl(repoUrl) : null;

    // Detect branches
    const mainResult = await execGit(['config', '--get', 'init.defaultBranch'], workDir);
    const mainBranch = mainResult.stdout || 'main';

    // Detect version
    const versionInfo = await detectVersion(workDir);

    // Resolve root folder (git root or workDir)
    const gitRootResult = await execGit(['rev-parse', '--show-toplevel'], workDir);
    const gitRoot = gitRootResult.exitCode === 0 ? gitRootResult.stdout : workDir;
    const rootFolder = normalizeForStorage(spec.root || gitRoot);

    // Create config path
    const configDir = join(rootFolder, '.claude', 'gitflow');
    mkdirSync(configDir, { recursive: true });
    const configPath = join(configDir, 'config.json');

    // Determine worktree settings
    let worktreeRootPath: string | undefined;
    if (spec.mode !== 'disabled') {
      worktreeRootPath = spec.mode === 'organized'
        ? join(rootFolder, '..', '.worktrees')
        : rootFolder;
    }

    // Create config
    const config = {
      version: '2.1.0',
      platform: {
        detected: platformInfo.platform,
        shell: platformInfo.shell,
        detectedAt: new Date().toISOString(),
      },
      workspace: {
        path: rootFolder,
        name: spec.name || repoName,
      },
      repository: {
        name: repoName,
        rootFolder,
        remoteUrl: repoUrl,
        defaultBranch: mainBranch,
        nameVariants: {
          camelCase: toCamelCase(repoName),
          PascalCase: toPascalCase(repoName),
          snake_case: toSnakeCase(repoName),
          UPPER_SNAKE: toUpperSnake(repoName),
          kebab_case: toKebabCase(repoName),
        },
      },
      git: {
        provider,
        branches: {
          main: mainBranch,
          develop: 'develop',
        },
        prefixes: {
          feature: 'feature/',
          release: 'release/',
          hotfix: 'hotfix/',
        },
      },
      worktree: {
        mode: spec.mode,
        rootPath: worktreeRootPath ? normalizeForStorage(worktreeRootPath) : undefined,
      },
    };

    // Write config
    writeFileSync(configPath, JSON.stringify(config, null, 2));

    // Repair worktree paths if needed
    if (spec.mode !== 'disabled') {
      await repairWorktreePaths(rootFolder, config);
    }

    return {
      success: true,
      config: config as any,
      structure: {
        configPath,
        worktreeDir: worktreeRootPath,
      },
      validation: {
        blockers: [],
        warnings: [],
      },
    };
  } catch (err) {
    return {
      success: false,
      error: (err as Error).message,
      validation: {
        blockers: [(err as Error).message],
        warnings: [],
      },
    };
  }
}

async function repairWorktreePaths(rootFolder: string, config: any): Promise<void> {
  const worktrees = await listWorktrees(rootFolder);
  for (const wt of worktrees) {
    if (wt.path && !existsSync(wt.path)) {
      // Worktree path is broken, would need git worktree repair here
      // For now, just log it
    }
  }
}

function toCamelCase(str: string): string {
  return str
    .replace(/[-_.]([a-z0-9])/gi, (_, char) => char.toUpperCase())
    .replace(/^([A-Z])/, (_, char) => char.toLowerCase());
}

function toPascalCase(str: string): string {
  return str
    .replace(/[-_.]([a-z0-9])/gi, (_, char) => char.toUpperCase())
    .replace(/^([a-z])/, (_, char) => char.toUpperCase());
}

function toSnakeCase(str: string): string {
  return str
    .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
    .replace(/[-.\s]/g, '_')
    .toLowerCase();
}

function toUpperSnake(str: string): string {
  return toSnakeCase(str).toUpperCase();
}

function toKebabCase(str: string): string {
  return str
    .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
    .replace(/[_.\s]/g, '-')
    .toLowerCase();
}
