import { type AttachmentHandle, downloadAndDecryptAttachment } from '@chat-app/shared/chat';
import { useState } from 'react';

import { getCachedAttachment, putCachedAttachment } from '../lib/attachmentCache';
import { supabase } from '../lib/supabase';
import { AlertIcon, SpinnerIcon } from './icons';

interface Props {
  handle: AttachmentHandle;
}

// Catch-all card for attachments without a richer renderer (zip, docx,
// txt, etc). Decrypt is deferred to first download click — these can be
// large and there's no inline preview to justify auto-fetching them.
export function AttachmentGeneric({ handle }: Props) {
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const download = async () => {
    if (busy) return;
    setBusy(true);
    setError(null);
    try {
      let blob = await getCachedAttachment(handle.id);
      if (!blob) {
        blob = await downloadAndDecryptAttachment({ client: supabase, handle });
        void putCachedAttachment(handle.id, blob);
      }
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = filenameFor(handle);
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      // Defer revoke so Safari has a chance to start the download.
      setTimeout(() => URL.revokeObjectURL(url), 60_000);
    } catch (err: unknown) {
      setError(err instanceof Error ? err.message : 'download failed');
    } finally {
      setBusy(false);
    }
  };

  return (
    <div className="mt-2 inline-flex w-[280px] items-center gap-2.5 rounded-lg border border-line bg-surface-2 p-2.5">
      <span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-md bg-accent/10 text-accent">
        <FileGlyph />
      </span>
      <div className="min-w-0 flex-1">
        <p className="truncate text-xs font-semibold text-fg">
          {prettyMime(handle.mimeType)}
        </p>
        <p className="truncate text-[10px] text-fg-muted">
          {formatSize(handle.sizeBytes)}
        </p>
        {error && (
          <p className="mt-0.5 inline-flex items-center gap-1 text-[10px] text-rose-500">
            <AlertIcon className="h-3 w-3" />
            <span>{error}</span>
          </p>
        )}
      </div>
      <button
        type="button"
        onClick={() => void download()}
        disabled={busy}
        aria-label="Download"
        title="Download"
        className="flex h-8 w-8 shrink-0 cursor-pointer items-center justify-center rounded-md border border-line bg-surface-3 text-fg transition hover:brightness-95 disabled:opacity-60"
      >
        {busy ? <SpinnerIcon className="h-4 w-4" /> : <DownloadGlyph />}
      </button>
    </div>
  );
}

function FileGlyph() {
  return (
    <svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor" aria-hidden="true">
      <path d="M3 2a1 1 0 011-1h6l3 3v10a1 1 0 01-1 1H4a1 1 0 01-1-1V2zm7 0v3h3l-3-3z" />
    </svg>
  );
}

function DownloadGlyph() {
  return (
    <svg viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M8 2v8M4 7l4 4 4-4M3 13h10" />
    </svg>
  );
}

function filenameFor(handle: AttachmentHandle): string {
  const ext = extFor(handle.mimeType);
  return 'attachment-' + handle.id.slice(0, 8) + (ext ? '.' + ext : '');
}

function extFor(mime: string): string | null {
  const map: Record<string, string> = {
    'application/zip': 'zip',
    'application/x-zip-compressed': 'zip',
    'application/x-7z-compressed': '7z',
    'application/x-tar': 'tar',
    'application/gzip': 'gz',
    'application/json': 'json',
    'application/xml': 'xml',
    'text/plain': 'txt',
    'text/markdown': 'md',
    'text/csv': 'csv',
    'application/msword': 'doc',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
    'application/vnd.ms-excel': 'xls',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
    'application/vnd.ms-powerpoint': 'ppt',
    'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx',
  };
  return map[mime] ?? null;
}

function prettyMime(mime: string): string {
  const ext = extFor(mime);
  if (ext) return ext.toUpperCase() + '-Datei';
  if (mime.startsWith('text/')) return 'Textdatei';
  return mime || 'Datei';
}

function formatSize(bytes: number): string {
  if (bytes < 1024) return bytes + ' B';
  if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(0) + ' KB';
  return (bytes / 1024 / 1024).toFixed(1) + ' MB';
}
