import type {
  ChangeType,
  DiffResult,
  RevisionChangeData,
} from './types';
import type { ScreenplayElementType } from '../screenplay/types';
import { detectElementType } from '../screenplay/detect';

interface LineDiffItem {
  type: ChangeType;
  line: string;
  oldLine?: string;
  originalLineIndex?: number;
}

function computeLineDiff(
  oldLines: string[],
  newLines: string[]
): LineDiffItem[] {
  const result: LineDiffItem[] = [];

  let oldIdx = 0;
  let newIdx = 0;

  while (oldIdx < oldLines.length || newIdx < newLines.length) {
    if (oldIdx < oldLines.length && newIdx < newLines.length) {
      const oldLine = oldLines[oldIdx]!;
      const newLine = newLines[newIdx]!;

      if (oldLine === newLine) {
        oldIdx++;
        newIdx++;
        continue;
      }

      result.push({
        type: 'modification',
        line: newLine,
        oldLine: oldLine,
        originalLineIndex: oldIdx,
      });
      oldIdx++;
      newIdx++;
    } else if (oldIdx < oldLines.length) {
      const oldLine = oldLines[oldIdx]!;
      result.push({
        type: 'deletion',
        line: oldLine,
        oldLine: oldLine,
        originalLineIndex: oldIdx,
      });
      oldIdx++;
    } else {
      const newLine = newLines[newIdx]!;
      result.push({ type: 'addition', line: newLine, originalLineIndex: newIdx });
      newIdx++;
    }
  }

  return result;
}

export function computeDiff(
  oldContent: string,
  newContent: string,
  revisionId: number
): DiffResult {
  const oldLines = oldContent.split('\n');
  const newLines = newContent.split('\n');

  const lineDiffs = computeLineDiff(oldLines, newLines);
  const changes: RevisionChangeData[] = [];

  let sceneCounter = 0;
  const linesPerPage = 55;

  for (let i = 0; i < lineDiffs.length; i++) {
    const diff = lineDiffs[i];
    if (!diff) continue;

    const lineToDetect = diff.line.trim();
    const elementType = lineToDetect
      ? (detectElementType(lineToDetect) as ScreenplayElementType)
      : null;

    if (elementType === 'sceneHeading') {
      sceneCounter++;
    }

    const lineNumber = (diff.originalLineIndex ?? i) + 1;
    const currentPage = Math.ceil(lineNumber / linesPerPage);

    const change: RevisionChangeData = {
      id: 0,
      revisionId,
      changeType: diff.type,
      elementType,
      oldContent: diff.oldLine || null,
      newContent: diff.type !== 'deletion' ? diff.line : null,
      sceneNumber: sceneCounter || null,
      lineNumber,
      pageNumber: currentPage,
      createdAt: new Date(),
    };

    changes.push(change);
  }

  const additions = changes.filter((c) => c.changeType === 'addition').length;
  const deletions = changes.filter((c) => c.changeType === 'deletion').length;
  const modifications = changes.filter(
    (c) => c.changeType === 'modification'
  ).length;

  return { additions, deletions, modifications, changes };
}

export function getChangeColor(changeType: ChangeType): string {
  switch (changeType) {
    case 'addition':
      return '#22c55e';
    case 'deletion':
      return '#ef4444';
    case 'modification':
      return '#f59e0b';
  }
}

export function getChangeBackgroundColor(changeType: ChangeType): string {
  switch (changeType) {
    case 'addition':
      return 'rgba(34, 197, 94, 0.15)';
    case 'deletion':
      return 'rgba(239, 68, 68, 0.15)';
    case 'modification':
      return 'rgba(245, 158, 11, 0.15)';
  }
}

export function formatChangeSummary(diff: DiffResult): string {
  const parts: string[] = [];
  if (diff.additions > 0) parts.push(`+${diff.additions} added`);
  if (diff.deletions > 0) parts.push(`-${diff.deletions} removed`);
  if (diff.modifications > 0) parts.push(`~${diff.modifications} modified`);
  return parts.join(', ') || 'No changes';
}
