import fs from 'fs';
import path from 'path';
import { execFile } from 'child_process';
import { promisify } from 'util';
import { LintResult, LintMessage } from './types.js';
import { PhpRuntimeOptions, resolvePhpRuntime } from './php-runtime.js';
import { hasUtf8Bom, ensureEncoding, assertFileSizeLimit } from './utils.js';

const execFileAsync = promisify(execFile);

function parsePhpLintError(output: string): LintMessage {
  const lineMatch = output.match(/on line\s+(\d+)/i);
  const line = lineMatch ? Number.parseInt(lineMatch[1], 10) : 1;

  return {
    line: Number.isFinite(line) ? line : 1,
    column: 1,
    severity: 'error',
    message: output.trim(),
    ruleId: 'php-syntax'
  };
}

export async function lintPHP(filePath: string, fix: boolean = false, projectPath?: string, runtimeOptions: PhpRuntimeOptions = {}): Promise<LintResult> {
  const absolutePath = path.resolve(filePath);

  if (!fs.existsSync(absolutePath)) {
    throw new Error(`File not found: ${absolutePath}`);
  }

  assertFileSizeLimit(absolutePath);

  const runtime = await resolvePhpRuntime(projectPath, runtimeOptions);
  const messages: LintMessage[] = [];
  let encodingModified = false;

  // PHP files must be UTF-8 without BOM.
  if (hasUtf8Bom(absolutePath)) {
    if (fix) {
      encodingModified = ensureEncoding(absolutePath, false);
    }

    if (!encodingModified) {
      messages.push({
        line: 1,
        column: 1,
        severity: 'error',
        message: 'PHP file must be encoded in UTF-8 without BOM.',
        ruleId: 'FILE_ENCODING_ERROR'
      });
    }
  }

  for (const warning of runtime.warnings) {
    messages.push({
      line: 1,
      column: 1,
      severity: 'info',
      message: warning,
      ruleId: 'PHP_RUNTIME_WARNING'
    });
  }

  if (fix) {
    messages.push({
      line: 1,
      column: 1,
      severity: 'info',
      message: 'PHP auto-fix currently supports only UTF-8 BOM removal when present.',
      ruleId: 'PHP_AUTO_FIX_UNSUPPORTED'
    });
  }

  try {
    await execFileAsync(runtime.phpPath, ['-l', absolutePath], { windowsHide: true, timeout: 8000 });
  } catch (error: any) {
    const output = `${error?.stdout || ''}\n${error?.stderr || ''}`.trim() || error?.message || 'Errore sconosciuto in php -l.';
    messages.push(parsePhpLintError(output));
  }

  return {
    filePath: absolutePath,
    messages,
    fixable: hasUtf8Bom(absolutePath) && !encodingModified,
    source: 'php -l',
    runtime: {
      phpPath: runtime.phpPath,
      version: runtime.version,
      source: runtime.source
    },
    candidates: runtime.candidates,
    warnings: runtime.warnings,
    userAction: runtime.userAction,
    suggestedEnv: runtime.suggestedEnv
  };
}
