import { useEffect, useState } from 'react';
import { Search, Trash2, X as XIcon, Copy, Check as CheckIcon, Download } from 'lucide-react';
import { Card, CardBody, CardHeader, CardTitle } from '@/components/ui/Card';
import { Button } from '@/components/ui/Button';
import { Tabs } from '@/components/ui/Tabs';
import { Input } from '@/components/ui/Input';
import { Loading, ErrorState, Empty } from '@/components/ui/States';
import { api } from '@/lib/api';
import { useQuery, useMutation } from '@/hooks/useQuery';
import { cn } from '@/lib/cn';
import { useConfirm } from '@/components/ConfirmProvider';
import { useApp } from '@/App';

const levels = [
  { value: 'all',     label: 'All' },
  { value: 'info',    label: 'Info' },
  { value: 'success', label: 'Success' },
  { value: 'warn',    label: 'Warnings' },
  { value: 'error',   label: 'Errors' },
] as const;
type Level = typeof levels[number]['value'];

const levelClass: Record<string, string> = {
  info:    'text-ink-300',
  success: 'text-emerald-400',
  warn:    'text-amber-400',
  error:   'text-red-400',
};

export function Logs() {
  const [level, setLevel]         = useState<Level>('all');
  const [q, setQ]                 = useState('');
  const [backupId, setBackupId]   = useState<string>('');
  const { logsTarget, clearLogsTarget } = useApp();

  // Honour a deep-link from elsewhere in the app (e.g. "View logs" on a
  // backup's details popover). Consume the target once so subsequent
  // navigation to /logs starts unfiltered again.
  useEffect(() => {
    if (logsTarget) {
      setBackupId(logsTarget);
      clearLogsTarget();
    }
  }, [logsTarget, clearLogsTarget]);

  const { data, isLoading, error, refetch } = useQuery(
    () => api.logs.list({
      level,
      search: q,
      backup_id: backupId || undefined,
      limit: 500,
    }),
    [level, q, backupId],
  );

  const clear = useMutation(() => api.logs.clear(), { onSuccess: refetch });
  const confirm = useConfirm();

  if (isLoading) return <Loading label="Loading logs…" />;
  if (error)     return <ErrorState error={error} onRetry={refetch} />;

  const lines = data?.items ?? [];

  return (
    <div className="space-y-4 max-w-[1400px]">
      <div className="flex items-center justify-between gap-3 flex-wrap">
        <Tabs value={level} onChange={setLevel} items={[...levels]} />
        <div className="flex items-center gap-2 flex-wrap">
          <div className="relative">
            <Search className="absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-ink-400" />
            <Input className="pl-8 w-72" placeholder="Search log…" value={q} onChange={(e) => setQ(e.target.value)} />
          </div>

          <Button variant="secondary" leftIcon={<Trash2 className="h-4 w-4" />} onClick={async () => {
            const ok = await confirm({
              title: 'Clear all logs?',
              description: 'All activity log entries will be permanently removed.',
              confirmLabel: 'Clear logs',
              tone: 'danger',
            });
            if (ok) clear.mutate(undefined as any);
          }}>Clear</Button>
        </div>
      </div>

      {/* Active filter chip — only when a backup is selected. Tap × to clear. */}
      {backupId && (
        <div className="flex items-center gap-2 text-xs">
          <span className="text-ink-500">Filtered to:</span>
          <button
            type="button"
            onClick={() => setBackupId('')}
            className="inline-flex items-center gap-1.5 h-6 px-2 rounded-full bg-brand-50 text-brand-800 border border-brand-200 hover:bg-brand-100"
          >
            <span className="font-mono">{backupId}</span>
            <XIcon className="h-3 w-3" />
          </button>
        </div>
      )}

      {lines.length === 0 ? (
        <Empty
          title="No log entries"
          hint={backupId ? `No entries recorded for ${backupId}.` : 'Run a backup to see activity logs here.'}
        />
      ) : (
        <Card>
          <CardHeader>
            <div>
              <CardTitle>Activity log</CardTitle>
              <p className="text-xs text-ink-500 mt-0.5">{lines.length} entries</p>
            </div>
          </CardHeader>
          <CardBody className="p-0">
            <div className="bg-ink-900 text-ink-100 rounded-b-2xl font-mono text-[12px] leading-7 max-h-[60vh] overflow-auto relative">
              {/* Sticky toolbar with Copy-all + Download buttons. Lets the
                  user grab the whole filtered feed in one click for bug
                  reports, instead of selecting + copying by hand. */}
              <LogFeedToolbar lines={lines} />

              <div className="p-5 pt-3">
                {lines.map((l) => (
                  <LogLine
                    key={l.id}
                    line={l}
                    activeBackupId={backupId}
                    onFilterBackup={(id) => setBackupId(id)}
                  />
                ))}
              </div>
            </div>
          </CardBody>
        </Card>
      )}
    </div>
  );
}

/**
 * One log row. Hover reveals a copy button on the right that copies the
 * formatted line to the clipboard ("[time] LEVEL  [backup_id]  message").
 * The copy button uses position:absolute so it overlays the row without
 * shifting the timestamp/level columns when it appears.
 */
function LogLine({
  line, activeBackupId, onFilterBackup,
}: {
  line: { id: number; created_at: string; level: string; backup_ext_id: string | null; message: string };
  activeBackupId: string;
  onFilterBackup: (id: string) => void;
}) {
  const [copied, setCopied] = useState(false);
  const timeStr = new Date(line.created_at + ' UTC').toLocaleTimeString();
  const formatted =
    `[${timeStr}] ${line.level.toUpperCase().padEnd(7)}` +
    (line.backup_ext_id ? `  ${line.backup_ext_id}` : '') +
    `  ${line.message}`;

  const copy = async () => {
    try {
      await navigator.clipboard.writeText(formatted);
      setCopied(true);
      window.setTimeout(() => setCopied(false), 1200);
    } catch { /* clipboard blocked; user can still select manually */ }
  };

  return (
    <div className="flex items-start gap-4 group relative pr-8 hover:bg-ink-800/40 -mx-2 px-2 rounded">
      <span className="text-ink-500 shrink-0">{timeStr}</span>
      <span className={cn('uppercase text-[10px] w-14 shrink-0 tracking-wider mt-1', levelClass[line.level])}>
        {line.level}
      </span>
      {line.backup_ext_id ? (
        <button
          type="button"
          onClick={() => onFilterBackup(line.backup_ext_id!)}
          title={`Filter logs to ${line.backup_ext_id}`}
          className={cn(
            'shrink-0 mt-0.5 inline-flex items-center h-5 px-1.5 rounded text-[10px] font-mono transition-colors',
            activeBackupId === line.backup_ext_id
              ? 'bg-brand-600 text-white'
              : 'bg-ink-800 text-ink-300 hover:bg-brand-700 hover:text-white',
          )}
        >
          {line.backup_ext_id}
        </button>
      ) : (
        <span className="shrink-0 mt-0.5 inline-flex items-center h-5 px-1.5 rounded text-[10px] text-ink-500 italic">
          system
        </span>
      )}
      <span className="text-ink-100 break-all flex-1">{line.message}</span>
      {/* Hover-revealed per-line copy. Hidden by default so the feed
          stays clean; opacity transitions in on group-hover. Position
          fixed-right so it never shifts the line text. */}
      <button
        type="button"
        onClick={copy}
        aria-label={copied ? 'Copied' : 'Copy this log line'}
        title={copied ? 'Copied!' : 'Copy line'}
        className={cn(
          'absolute right-1 top-1 h-6 w-6 grid place-items-center rounded-md transition-all shrink-0',
          copied
            ? 'opacity-100 bg-emerald-600 text-white'
            : 'opacity-0 group-hover:opacity-100 bg-ink-800 text-ink-300 hover:bg-ink-700 hover:text-white',
        )}
      >
        {copied ? <CheckIcon className="h-3 w-3" /> : <Copy className="h-3 w-3" />}
      </button>
    </div>
  );
}

/**
 * Top-right floating toolbar inside the log feed. "Copy all" grabs the
 * currently-filtered window of lines as plain text — great for pasting
 * into a bug report or support email. "Download" saves the same text
 * as a .log file for longer feeds you don't want in your clipboard.
 */
function LogFeedToolbar({
  lines,
}: {
  lines: Array<{ id: number; created_at: string; level: string; backup_ext_id: string | null; message: string }>;
}) {
  const [copied, setCopied] = useState(false);

  // Build the full plaintext blob once on demand (only when the user
  // clicks). Avoids serialising on every render for big feeds.
  const buildText = () =>
    lines.map((l) => {
      const t = new Date(l.created_at + ' UTC').toLocaleString();
      const idPart = l.backup_ext_id ? ` ${l.backup_ext_id}` : '';
      return `[${t}] ${l.level.toUpperCase().padEnd(7)}${idPart}  ${l.message}`;
    }).join('\n');

  const copyAll = async () => {
    try {
      await navigator.clipboard.writeText(buildText());
      setCopied(true);
      window.setTimeout(() => setCopied(false), 1500);
    } catch { /* clipboard blocked */ }
  };

  const download = () => {
    const blob = new Blob([buildText()], { type: 'text/plain' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `backreload-logs-${new Date().toISOString().slice(0, 19).replace(/[:T]/g, '-')}.log`;
    document.body.appendChild(a);
    a.click();
    a.remove();
    URL.revokeObjectURL(url);
  };

  if (lines.length === 0) return null;

  return (
    <div className="sticky top-0 z-10 bg-ink-900/95 backdrop-blur-sm flex items-center justify-end gap-2 px-3 py-2 border-b border-ink-800">
      <button
        type="button"
        onClick={copyAll}
        title={copied ? 'Copied!' : `Copy all ${lines.length} line(s)`}
        className={cn(
          'inline-flex items-center gap-1.5 h-7 px-2.5 rounded-md text-[11px] font-medium transition-colors',
          copied
            ? 'bg-emerald-600 text-white'
            : 'bg-ink-800 text-ink-100 hover:bg-ink-700',
        )}
      >
        {copied
          ? <><CheckIcon className="h-3 w-3" /> Copied</>
          : <><Copy className="h-3 w-3" /> Copy all</>}
      </button>
      <button
        type="button"
        onClick={download}
        title="Download the current log window as a .log file"
        className="inline-flex items-center gap-1.5 h-7 px-2.5 rounded-md text-[11px] font-medium bg-ink-800 text-ink-100 hover:bg-ink-700 transition-colors"
      >
        <Download className="h-3 w-3" />
        Download
      </button>
    </div>
  );
}
