'use client';

import { useMemo, useState } from 'react';
import { ChevronDown, ChevronRight } from 'lucide-react';

import { Button } from '@spoon/ui';

import type { DiffMode } from './diff-file-view';
import type { DiffFileStatus, ParsedDiffFile } from './diff-utils';
import { DiffFileView, useDiffTheme } from './diff-file-view';
import { parseDiffFiles } from './diff-utils';

const statusBadge: Record<
  DiffFileStatus,
  { label: string; className: string }
> = {
  added: { label: 'Added', className: 'bg-emerald-500/15 text-emerald-500' },
  deleted: { label: 'Deleted', className: 'bg-red-500/15 text-red-500' },
  modified: { label: 'Modified', className: 'bg-amber-500/15 text-amber-500' },
  renamed: { label: 'Renamed', className: 'bg-sky-500/15 text-sky-500' },
};

const totals = (files: ParsedDiffFile[]) =>
  files.reduce(
    (acc, file) => ({
      additions: acc.additions + file.additions,
      deletions: acc.deletions + file.deletions,
    }),
    { additions: 0, deletions: 0 },
  );

const FileCard = ({
  file,
  mode,
  theme,
  defaultOpen,
}: {
  file: ParsedDiffFile;
  mode: DiffMode;
  theme: 'light' | 'dark';
  defaultOpen: boolean;
}) => {
  const [open, setOpen] = useState(defaultOpen);
  const badge = statusBadge[file.status];
  return (
    <div className='border-border overflow-hidden rounded-md border'>
      <button
        type='button'
        onClick={() => setOpen((value) => !value)}
        className='bg-muted/40 hover:bg-muted/70 flex w-full items-center gap-2 px-3 py-2 text-left transition-colors'
      >
        {open ? (
          <ChevronDown className='text-muted-foreground size-4 flex-none' />
        ) : (
          <ChevronRight className='text-muted-foreground size-4 flex-none' />
        )}
        <span className='min-w-0 flex-1 truncate font-mono text-xs'>
          {file.status === 'renamed' && file.oldPath !== file.newPath ? (
            <>
              <span className='text-muted-foreground'>{file.oldPath} → </span>
              {file.newPath}
            </>
          ) : (
            file.displayPath
          )}
        </span>
        <span
          className={`flex-none rounded px-1.5 py-0.5 text-[10px] font-medium ${badge.className}`}
        >
          {badge.label}
        </span>
        <span className='flex-none font-mono text-xs'>
          {file.additions > 0 ? (
            <span className='text-emerald-500'>+{file.additions}</span>
          ) : null}{' '}
          {file.deletions > 0 ? (
            <span className='text-red-500'>−{file.deletions}</span>
          ) : null}
        </span>
      </button>
      {open ? (
        <div className='overflow-x-auto'>
          <DiffFileView file={file} mode={mode} theme={theme} />
        </div>
      ) : null}
    </div>
  );
};

export const DiffViewer = ({
  diff,
  focusedPath,
  onRefresh,
  onClearFocusedPath,
}: {
  diff: string;
  focusedPath?: string;
  onRefresh: () => Promise<void>;
  onClearFocusedPath?: () => void;
}) => {
  const [mode, setMode] = useState<DiffMode>('unified');
  const theme = useDiffTheme();

  const files = useMemo(() => parseDiffFiles(diff), [diff]);
  const normalizedFocus = focusedPath?.replace(/^\.\/+/, '');
  const visibleFiles = useMemo(
    () =>
      normalizedFocus
        ? files.filter(
            (file) =>
              file.displayPath === normalizedFocus ||
              file.newPath === normalizedFocus ||
              file.oldPath === normalizedFocus,
          )
        : files,
    [files, normalizedFocus],
  );
  const stats = totals(visibleFiles);

  return (
    <div className='flex h-full min-h-0 flex-col'>
      <div className='border-border flex h-12 items-center justify-between gap-3 border-b px-3'>
        <div className='min-w-0'>
          <p className='truncate text-sm font-medium'>
            {focusedPath ? `Diff: ${focusedPath}` : 'Diff viewer'}
          </p>
          <p className='text-muted-foreground truncate text-xs'>
            {visibleFiles.length > 0
              ? `${visibleFiles.length} ${visibleFiles.length === 1 ? 'file' : 'files'}, `
              : ''}
            <span className='text-emerald-500'>+{stats.additions}</span>{' '}
            <span className='text-red-500'>−{stats.deletions}</span>
          </p>
        </div>
        <div className='flex flex-none items-center gap-2'>
          <div className='border-border flex items-center rounded-md border p-0.5'>
            <button
              type='button'
              onClick={() => setMode('unified')}
              className={`rounded px-2 py-1 text-xs font-medium transition-colors ${
                mode === 'unified'
                  ? 'bg-muted text-foreground'
                  : 'text-muted-foreground hover:text-foreground'
              }`}
            >
              Unified
            </button>
            <button
              type='button'
              onClick={() => setMode('split')}
              className={`rounded px-2 py-1 text-xs font-medium transition-colors ${
                mode === 'split'
                  ? 'bg-muted text-foreground'
                  : 'text-muted-foreground hover:text-foreground'
              }`}
            >
              Split
            </button>
          </div>
          {focusedPath ? (
            <Button
              type='button'
              variant='ghost'
              size='sm'
              onClick={onClearFocusedPath}
            >
              Show all
            </Button>
          ) : null}
          <Button type='button' variant='outline' size='sm' onClick={onRefresh}>
            Refresh
          </Button>
        </div>
      </div>
      {visibleFiles.length > 0 ? (
        <div className='flex flex-1 flex-col gap-3 overflow-y-auto p-3'>
          {visibleFiles.map((file, index) => (
            <FileCard
              key={file.id}
              file={file}
              mode={mode}
              theme={theme}
              defaultOpen={visibleFiles.length <= 10 || index < 5}
            />
          ))}
        </div>
      ) : (
        <div className='text-muted-foreground flex flex-1 items-center justify-center text-sm'>
          {focusedPath
            ? 'No diff is recorded for this file yet.'
            : 'No workspace diff yet.'}
        </div>
      )}
    </div>
  );
};
