import { useMemo, useState } from 'react'
import { cn } from '../../lib/utils'

export interface FileDiff {
  path: string
  oldPath?: string
  additions: number
  deletions: number
  patch: string
}

interface DiffViewerProps {
  files: FileDiff[]
}

export function DiffViewer({ files }: DiffViewerProps) {
  if (!files.length) {
    return (
      <div className="text-center py-12 text-[var(--c-muted)] text-sm">
        No changes in this diff.
      </div>
    )
  }

  return (
    <div className="flex flex-col gap-4">
      {files.map(file => (
        <FileDiffBlock key={file.path} file={file} />
      ))}
    </div>
  )
}

function FileDiffBlock({ file }: { file: FileDiff }) {
  const [collapsed, setCollapsed] = useState(false)
  const lines = useMemo(() => parsePatch(file.patch), [file.patch])

  return (
    <div className="border border-[var(--c-border)] rounded overflow-hidden font-mono text-xs">
      {/* File header */}
      <div className="flex items-center justify-between px-3 py-2 bg-[var(--c-surface-muted)] border-b border-[var(--c-border)] gap-2">
        <button
          onClick={() => setCollapsed(c => !c)}
          className="flex items-center gap-2 text-left min-w-0"
        >
          <svg
            width="12" height="12" fill="none" stroke="currentColor" strokeWidth="2"
            viewBox="0 0 24 24"
            className={cn('shrink-0 transition-transform', collapsed && '-rotate-90')}
          >
            <path strokeLinecap="round" strokeLinejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
          </svg>
          <span className="font-semibold text-[var(--c-text)] truncate">{file.path}</span>
          {file.oldPath && file.oldPath !== file.path && (
            <span className="text-[var(--c-muted)] text-[10px] shrink-0">← {file.oldPath}</span>
          )}
        </button>
        <div className="flex items-center gap-2 shrink-0 text-[11px]">
          {file.additions > 0 && (
            <span className="text-[var(--c-success)] font-semibold">+{file.additions}</span>
          )}
          {file.deletions > 0 && (
            <span className="text-[var(--c-danger)] font-semibold">-{file.deletions}</span>
          )}
        </div>
      </div>

      {/* Diff lines */}
      {!collapsed && (
        <div className="overflow-x-auto">
          <table className="w-full border-collapse text-[11px] leading-5">
            <tbody>
              {lines.map((line, i) => (
                <DiffLine key={i} line={line} />
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  )
}

type LineType = 'added' | 'removed' | 'context' | 'hunk'

interface ParsedLine {
  type: LineType
  oldNo?: number
  newNo?: number
  content: string
}

function parsePatch(patch: string): ParsedLine[] {
  const lines: ParsedLine[] = []
  let oldNo = 0
  let newNo = 0

  for (const raw of patch.split('\n')) {
    if (raw.startsWith('@@')) {
      // @@ -oldStart,oldCount +newStart,newCount @@
      const match = raw.match(/@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/)
      if (match) {
        oldNo = parseInt(match[1], 10)
        newNo = parseInt(match[2], 10)
      }
      lines.push({ type: 'hunk', content: raw })
      continue
    }
    if (raw.startsWith('+') && !raw.startsWith('+++')) {
      lines.push({ type: 'added', newNo: newNo++, content: raw.slice(1) })
    } else if (raw.startsWith('-') && !raw.startsWith('---')) {
      lines.push({ type: 'removed', oldNo: oldNo++, content: raw.slice(1) })
    } else if (!raw.startsWith('\\') && !raw.startsWith('---') && !raw.startsWith('+++')) {
      lines.push({ type: 'context', oldNo: oldNo++, newNo: newNo++, content: raw })
    }
  }
  return lines
}

function DiffLine({ line }: { line: ParsedLine }) {
  if (line.type === 'hunk') {
    return (
      <tr className="bg-[var(--c-brand-tint)]">
        <td className="px-2 py-0.5 text-[var(--c-muted)] select-none w-10 text-right" />
        <td className="px-2 py-0.5 text-[var(--c-muted)] select-none w-10 text-right" />
        <td className="px-3 py-0.5 text-[var(--c-brand)] font-semibold whitespace-pre">{line.content}</td>
      </tr>
    )
  }

  const bg = line.type === 'added'
    ? 'bg-[#E3FCEF]'
    : line.type === 'removed'
    ? 'bg-[var(--c-danger-tint)]'
    : ''

  const gutter = line.type === 'added'
    ? 'bg-[#ABF5D1] text-[#006644]'
    : line.type === 'removed'
    ? 'bg-[#FFBDAD] text-[var(--c-danger-dark)]'
    : 'bg-[var(--c-surface-muted)] text-[var(--c-muted)]'

  const prefix = line.type === 'added' ? '+' : line.type === 'removed' ? '-' : ' '

  return (
    <tr className={cn('group', bg)}>
      <td className={cn('px-2 py-0.5 select-none w-10 text-right tabular-nums', gutter)}>
        {line.type !== 'added' ? line.oldNo : ''}
      </td>
      <td className={cn('px-2 py-0.5 select-none w-10 text-right tabular-nums', gutter)}>
        {line.type !== 'removed' ? line.newNo : ''}
      </td>
      <td className="px-3 py-0.5 whitespace-pre">
        <span className="select-none mr-2 opacity-50">{prefix}</span>
        {line.content}
      </td>
    </tr>
  )
}
