/**
 * commit CLI execute — Execution logic, no validation
 */

import type { CommitSpec, CommitResult } from './types.js';
import { getCurrentBranch, getStatus, addFiles, commit, push, getLog, getDiffFiles } from '../lib/git.js';
import { detectBranchType } from '../lib/branch.js';
import { validateEfCore } from '../lib/efcore.js';
import { detectVersion } from '../lib/version.js';

function generateCommitMessage(branch: string, version?: string): string {
  const type = detectBranchType(branch);
  let scope = branch.replace(/^(feature|release|hotfix)\//, '');
  scope = scope.split('-')[0];
  const tag = version ? `[v${version}] ` : '';

  switch (type) {
    case 'feature':
      return `feat(${scope}): ${tag}update files`;
    case 'hotfix':
      return `fix(${scope}): ${tag}update files`;
    case 'release':
      return `chore(${scope}): ${tag}update files`;
    default:
      return `chore: update files`;
  }
}

export async function execute(spec: CommitSpec, cwd?: string): Promise<CommitResult> {
  try {
    const branch = await getCurrentBranch(cwd);

    if (branch === 'main' || branch === 'master') {
      return {
        success: false,
        error: 'Cannot commit directly to main branch',
        branch,
        filesChanged: 0,
        pushed: false,
      };
    }

    if (branch === 'develop' || branch === 'development') {
      // warning, not blocker
    }

    const status = await getStatus(cwd);
    if (!status.dirty) {
      return {
        success: false,
        error: 'No changes to commit',
        branch,
        filesChanged: 0,
        pushed: false,
      };
    }

    let efcoreValidation = undefined;
    if (!spec.noEfcore) {
      const changedFiles = [...status.staged, ...status.modified, ...status.untracked];
      const validation = validateEfCore(changedFiles);
      efcoreValidation = validation;

      if (validation.detected && !validation.valid) {
        return {
          success: false,
          error: `EF Core validation failed: ${validation.missing.join(', ')}`,
          branch,
          filesChanged: changedFiles.length,
          efcore: validation,
          pushed: false,
        };
      }

      if (validation.detected && validation.destructive) {
        return {
          success: false,
          error: `Destructive EF Core operations detected: ${validation.destructiveOps.join(', ')}`,
          branch,
          filesChanged: changedFiles.length,
          efcore: validation,
          pushed: false,
        };
      }
    }

    const filesChanged = status.staged.length + status.modified.length + status.untracked.length;
    await addFiles(['.'], cwd);

    let version: string | undefined;
    if (!spec.message) {
      const projectDir = cwd || process.cwd();
      const versionInfo = await detectVersion(projectDir);
      if (versionInfo.current !== '0.0.0') {
        version = versionInfo.current;
      }
    }
    const message = spec.message || generateCommitMessage(branch, version);
    const commitResult = await commit(message, cwd);

    if (commitResult.exitCode !== 0) {
      return {
        success: false,
        error: `Commit failed: ${commitResult.stderr || commitResult.stdout}`,
        branch,
        filesChanged,
        efcore: efcoreValidation,
        pushed: false,
      };
    }

    let hash = '';
    try {
      const logs = await getLog(1, '%H', cwd);
      hash = logs[0] || '';
    } catch {
      hash = 'unknown';
    }

    let pushed = false;
    if (spec.push) {
      const pushResult = await push(branch, cwd);
      pushed = pushResult.exitCode === 0;
    }

    return {
      success: true,
      branch,
      commit: {
        hash,
        message,
      },
      filesChanged,
      efcore: efcoreValidation,
      pushed,
    };
  } catch (err: unknown) {
    return {
      success: false,
      error: (err as Error).message,
      branch: '',
      filesChanged: 0,
      pushed: false,
    };
  }
}
