type CommentStyle = 'c-block' | 'hash' | 'sql' | 'percent' | 'semicolon' | 'xml' | 'sidecar';

const EXTENSION_MAP: Record<string, CommentStyle> = {
  '.java': 'c-block',
  '.kt': 'c-block',
  '.scala': 'c-block',
  '.c': 'c-block',
  '.cpp': 'c-block',
  '.h': 'c-block',
  '.cs': 'c-block',
  '.go': 'c-block',
  '.js': 'c-block',
  '.ts': 'c-block',
  '.tsx': 'c-block',
  '.jsx': 'c-block',
  '.swift': 'c-block',
  '.php': 'c-block',
  '.rs': 'c-block',
  '.groovy': 'c-block',
  '.py': 'hash',
  '.rb': 'hash',
  '.sh': 'hash',
  '.bash': 'hash',
  '.zsh': 'hash',
  '.pl': 'hash',
  '.pm': 'hash',
  '.r': 'hash',
  '.yaml': 'hash',
  '.yml': 'hash',
  '.sql': 'sql',
  '.ada': 'sql',
  '.adb': 'sql',
  '.ads': 'sql',
  '.hs': 'sql',
  '.lua': 'sql',
  '.erl': 'percent',
  '.hrl': 'percent',
  '.pro': 'percent',
  '.lisp': 'semicolon',
  '.clj': 'semicolon',
  '.cljs': 'semicolon',
  '.el': 'semicolon',
  '.json': 'sidecar',
  '.xml': 'xml',
  '.csproj': 'xml',
  '.fsproj': 'xml',
  '.vbproj': 'xml',
  '.props': 'xml',
  '.targets': 'xml',
  '.config': 'xml',
  '.xaml': 'xml',
  '.resx': 'xml',
  '.nuspec': 'xml',
  '.vsixmanifest': 'xml',
  '.html': 'sidecar',
  '.htm': 'sidecar',
  '.wasm': 'sidecar',
};

const SIDE_CAR_FORMATS = new Set<CommentStyle>(['sidecar']);
const SCRIBA_MARKER_VERSION = 1;

export interface MarkerMetadata {
  conversionId: string;
  sourceLanguage: string;
  targetLanguage: string;
  timestamp: string;
  platformVersion: string;
}

export interface MarkerResult {
  marked: string;
  usedSidecar: boolean;
  sidecarPath?: string;
  sidecarContent?: string;
}

function extensionFor(filePath: string): string {
  const normalized = (filePath || '').replace(/\\/g, '/').toLowerCase();
  const fileName = normalized.split('/').pop() ?? '';
  if (fileName === 'makefile') return '.makefile';
  const lastDot = fileName.lastIndexOf('.');
  if (lastDot < 0) return '';
  return fileName.slice(lastDot);
}

export function getCommentStyle(filePath: string): CommentStyle {
  const ext = extensionFor(filePath);
  return EXTENSION_MAP[ext] ?? 'c-block';
}

export function buildMarkerBlock(style: CommentStyle, meta: MarkerMetadata): string {
  const lines = [
    '@scriba-ai-generated: true',
    `@scriba-marker-version: ${SCRIBA_MARKER_VERSION}`,
    `@scriba-source-language: ${meta.sourceLanguage || 'unknown'}`,
    `@scriba-target-language: ${meta.targetLanguage || 'unknown'}`,
    `@scriba-conversion-id: ${meta.conversionId || 'unknown'}`,
    `@scriba-timestamp: ${meta.timestamp || new Date().toISOString()}`,
    `@scriba-platform-version: ${meta.platformVersion || '1.0.0'}`,
  ];

  if (style === 'c-block') {
    return `/*\n${lines.map((line) => ` * ${line}`).join('\n')}\n */\n`;
  }
  if (style === 'hash') {
    return `${lines.map((line) => `# ${line}`).join('\n')}\n`;
  }
  if (style === 'sql') {
    return `${lines.map((line) => `-- ${line}`).join('\n')}\n`;
  }
  if (style === 'percent') {
    return `${lines.map((line) => `% ${line}`).join('\n')}\n`;
  }
  if (style === 'semicolon') {
    return `${lines.map((line) => `; ${line}`).join('\n')}\n`;
  }
  if (style === 'xml') {
    return `<!--\n${lines.map((line) => `  ${line}`).join('\n')}\n-->\n`;
  }
  return JSON.stringify(
    {
      scribaMarkerVersion: SCRIBA_MARKER_VERSION,
      aiGenerated: true,
      conversionId: meta.conversionId || 'unknown',
      sourceLanguage: meta.sourceLanguage || 'unknown',
      targetLanguage: meta.targetLanguage || 'unknown',
      timestamp: meta.timestamp || new Date().toISOString(),
      platformVersion: meta.platformVersion || '1.0.0',
    },
    null,
    2
  );
}

function detectInsertionOffset(content: string): number {
  const lines = content.split('\n');
  if (lines.length === 0) return 0;

  let cursor = 0;
  if ((lines[0] || '').startsWith('#!')) cursor = 1;
  else if ((lines[0] || '').trim().startsWith('<?xml')) cursor = 1;
  else if (/^\s*#\s*-\*-\s*coding:/i.test(lines[0] || '')) cursor = 1;

  const maxProbe = Math.min(lines.length, 30);
  let licenseCursor = cursor;
  let seenLicenseLine = false;
  while (licenseCursor < maxProbe) {
    const line = lines[licenseCursor] || '';
    if (line.trim() === '') {
      licenseCursor += 1;
      continue;
    }
    if (
      /^\s*(?:<!--|[/*#;%-])?\s*(copyright|license|spdx|licensed under)\b/i.test(line)
    ) {
      seenLicenseLine = true;
      licenseCursor += 1;
      continue;
    }
    break;
  }
  // Only advance past empty lines if a license block was actually found;
  // otherwise shebang/XML files with trailing blank lines before code would
  // have the marker pushed too far down.
  return seenLicenseLine ? licenseCursor : cursor;
}

function insertAtOffset(content: string, marker: string, offset: number): string {
  const lines = content.split('\n');
  const before = lines.slice(0, offset).join('\n');
  const after = lines.slice(offset).join('\n');
  if (!before) return `${marker}${after}`;
  if (!after) return `${before}\n${marker}`;
  return `${before}\n${marker}${after}`;
}

export function hasMarker(content: string): boolean {
  if (!content) return false;
  return /@scriba-ai-generated:\s*true/.test(content) || /"aiGenerated"\s*:\s*true/.test(content);
}

export function applyMarker(filePath: string, content: string, meta: MarkerMetadata): MarkerResult {
  const safeContent = content ?? '';
  if (hasMarker(safeContent)) {
    return { marked: safeContent, usedSidecar: false };
  }

  const style = getCommentStyle(filePath);
  if (SIDE_CAR_FORMATS.has(style)) {
    const sidecarPath = `${filePath}.scriba-marker.json`;
    const sidecarContent = buildMarkerBlock('sidecar', meta);
    return {
      marked: safeContent,
      usedSidecar: true,
      sidecarPath,
      sidecarContent,
    };
  }

  const marker = buildMarkerBlock(style, meta);
  const offset = detectInsertionOffset(safeContent);
  return {
    marked: insertAtOffset(safeContent, marker, offset),
    usedSidecar: false,
  };
}

export function buildManifest(meta: MarkerMetadata, filePaths: string[]): string {
  return JSON.stringify(
    {
      scribaMarkerVersion: SCRIBA_MARKER_VERSION,
      aiGenerated: true,
      conversionId: meta.conversionId,
      sourceLanguage: meta.sourceLanguage,
      targetLanguage: meta.targetLanguage,
      timestamp: meta.timestamp,
      platformVersion: meta.platformVersion,
      files: [...filePaths].sort(),
    },
    null,
    2
  );
}

export function warnMarkerStripped(filePath: string, conversionId: string): void {
  console.warn(
    `[scriba-ai-marker] marker missing from "${filePath}" for conversion "${conversionId}"`
  );
}
