import { useEffect, useMemo, useState } from 'react';
import { useT } from '../i18n';
import type { Dict } from '../i18n/types';
import { projectFileUrl } from '../providers/registry';
import type { ProjectFile, ProjectFileKind } from '../types';
import { Icon } from './Icon';

type TranslateFn = (key: keyof Dict, vars?: Record<string, string | number>) => string;

interface Props {
  projectId: string;
  files: ProjectFile[];
  onRefreshFiles: () => Promise<void> | void;
  onOpenFile: (name: string) => void;
  onDeleteFile: (name: string) => void;
  onUpload: () => void;
  onPaste: () => void;
  onNewSketch: () => void;
}

type Section = 'pages' | 'scripts' | 'images' | 'sketches' | 'other';

const SECTION_LABEL_KEY: Record<Section, keyof Dict> = {
  pages: 'designFiles.sectionPages',
  scripts: 'designFiles.sectionScripts',
  images: 'designFiles.sectionImages',
  sketches: 'designFiles.sectionSketches',
  other: 'designFiles.sectionOther',
};

const SECTION_ORDER: Section[] = ['pages', 'sketches', 'scripts', 'images', 'other'];

/**
 * Full-panel browser for a project's `.ocd/projects/<id>/` folder. Mirrors
 * Claude Design's "Design Files" surface: grouped sections, hover-revealed
 * row menu, drop-files footer, and (when a row is selected) a right-side
 * preview pane. Triggered as a sticky first tab in FileWorkspace.
 */
export function DesignFilesPanel({
  projectId,
  files,
  onRefreshFiles,
  onOpenFile,
  onDeleteFile,
  onUpload,
  onPaste,
  onNewSketch,
}: Props) {
  const t = useT();
  const [refreshing, setRefreshing] = useState(false);
  const [hover, setHover] = useState<string | null>(null);
  const [menuPos, setMenuPos] = useState<{ name: string; top: number; left: number } | null>(null);
  const [preview, setPreview] = useState<string | null>(null);

  const grouped = useMemo(() => {
    const groups: Record<Section, ProjectFile[]> = {
      pages: [],
      sketches: [],
      scripts: [],
      images: [],
      other: [],
    };
    const sorted = [...files].sort((a, b) => b.mtime - a.mtime);
    for (const f of sorted) {
      groups[sectionFor(f)].push(f);
    }
    return groups;
  }, [files]);

  const previewFile = useMemo(
    () => files.find((f) => f.name === preview) ?? null,
    [preview, files],
  );

  // Close the row menu on outside click / escape.
  useEffect(() => {
    if (!menuPos) return;
    const close = () => setMenuPos(null);
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') close();
    };
    window.addEventListener('mousedown', close);
    window.addEventListener('keydown', onKey);
    return () => {
      window.removeEventListener('mousedown', close);
      window.removeEventListener('keydown', onKey);
    };
  }, [menuPos]);

  async function handleRefresh() {
    setRefreshing(true);
    try {
      await onRefreshFiles();
    } finally {
      setRefreshing(false);
    }
  }

  return (
    <div className={`df-panel ${preview ? '' : 'no-preview'}`}>
      <div className="df-main">
        <div className="df-head">
          <button
            type="button"
            className="icon-only"
            onClick={() => setPreview(null)}
            title={t('designFiles.up')}
            aria-label={t('designFiles.back')}
          >
            ↑
          </button>
          <button
            type="button"
            className="icon-only"
            onClick={() => void handleRefresh()}
            disabled={refreshing}
            title={t('designFiles.refresh')}
            aria-label={t('designFiles.refresh')}
          >
            <Icon name={refreshing ? 'spinner' : 'reload'} size={14} />
          </button>
          <span className="crumbs">{t('designFiles.crumbs')}</span>
          <div className="df-actions">
            <button type="button" onClick={onNewSketch} title={t('designFiles.newSketch')}>
              <Icon name="pencil" size={13} />
              <span>{t('designFiles.newSketch')}</span>
            </button>
            <button type="button" onClick={onPaste} title={t('designFiles.paste.title')}>
              <Icon name="copy" size={13} />
              <span>{t('designFiles.paste.label')}</span>
            </button>
            <button type="button" onClick={onUpload} title={t('designFiles.upload.title')}>
              <Icon name="upload" size={13} />
              <span>{t('designFiles.upload.label')}</span>
            </button>
          </div>
        </div>
        <div className="df-body">
          {files.length === 0 ? (
            <div className="df-empty">{t('designFiles.empty')}</div>
          ) : (
            SECTION_ORDER.filter((s) => grouped[s].length > 0).map((section) => (
              <div className="df-section" key={section}>
                <div className="df-section-label">
                  {t(SECTION_LABEL_KEY[section])}
                </div>
                {grouped[section].map((f) => {
                  const active = preview === f.name;
                  const isHovered = hover === f.name;
                  return (
                    <button
                      key={f.name}
                      type="button"
                      className={`df-row ${active ? 'active' : ''}`}
                      onMouseEnter={() => setHover(f.name)}
                      onMouseLeave={() => setHover((c) => (c === f.name ? null : c))}
                      onClick={() => setPreview(f.name)}
                      onDoubleClick={() => onOpenFile(f.name)}
                    >
                      <span className="df-row-icon" data-kind={f.kind} aria-hidden>
                        {kindGlyph(f.kind)}
                      </span>
                      <span className="df-row-name-wrap">
                        <span className="df-row-name">{f.name}</span>
                        <span className="df-row-sub">{kindLabel(f.kind, t)}</span>
                      </span>
                      <span className="df-row-time">{relativeTime(f.mtime, t)}</span>
                      <span
                        className="df-row-menu"
                        style={isHovered || active ? { opacity: 1 } : undefined}
                        role="button"
                        aria-label={t('designFiles.rowMenu')}
                        onClick={(e) => {
                          e.stopPropagation();
                          const rect = (e.target as HTMLElement)
                            .closest('.df-row-menu')
                            ?.getBoundingClientRect();
                          setMenuPos({
                            name: f.name,
                            top: (rect?.bottom ?? 0) + 4,
                            left: (rect?.right ?? 0) - 160,
                          });
                        }}
                      >
                        ⋯
                      </span>
                    </button>
                  );
                })}
              </div>
            ))
          )}
          <div className="df-drop">
            <span className="label">{t('designFiles.dropTitle')}</span>
            <span className="desc">{t('designFiles.dropDesc')}</span>
          </div>
        </div>
      </div>
      {preview && previewFile ? (
        <DfPreview
          projectId={projectId}
          file={previewFile}
          onOpen={() => onOpenFile(previewFile.name)}
          onClose={() => setPreview(null)}
        />
      ) : null}
      {menuPos ? (
        <div
          className="df-row-popover"
          style={{ top: menuPos.top, left: menuPos.left }}
          onMouseDown={(e) => e.stopPropagation()}
        >
          <button
            type="button"
            onClick={() => {
              const name = menuPos.name;
              setMenuPos(null);
              onOpenFile(name);
            }}
          >
            {t('designFiles.openInTab')}
          </button>
          <a
            href={projectFileUrl(projectId, menuPos.name)}
            download={menuPos.name}
            style={{ textDecoration: 'none' }}
          >
            <button type="button" onClick={() => setMenuPos(null)}>
              {t('designFiles.download')}
            </button>
          </a>
          <button
            type="button"
            className="danger"
            onClick={() => {
              const name = menuPos.name;
              setMenuPos(null);
              onDeleteFile(name);
            }}
          >
            {t('designFiles.delete')}
          </button>
        </div>
      ) : null}
    </div>
  );
}

function DfPreview({
  projectId,
  file,
  onOpen,
  onClose,
}: {
  projectId: string;
  file: ProjectFile;
  onOpen: () => void;
  onClose: () => void;
}) {
  const t = useT();
  const url = projectFileUrl(projectId, file.name);
  return (
    <aside className="df-preview">
      <div className="df-preview-thumb">
        {file.kind === 'image' || file.kind === 'sketch' ? (
          <img src={`${url}?v=${Math.round(file.mtime)}`} alt={file.name} />
        ) : file.kind === 'html' ? (
          <iframe title={file.name} src={url} sandbox="allow-scripts" />
        ) : (
          <div
            style={{
              width: '100%',
              height: '100%',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              color: 'var(--text-faint)',
              fontSize: 38,
            }}
          >
            {kindGlyph(file.kind)}
          </div>
        )}
      </div>
      <div className="df-preview-meta">
        <button
          type="button"
          className="ghost"
          onClick={onOpen}
          style={{ alignSelf: 'flex-start' }}
        >
          <Icon name="eye" size={13} />
          <span>{t('designFiles.previewOpen')}</span>
        </button>
        <div className="df-preview-name">{file.name}</div>
        <div className="df-preview-kind">{kindLabel(file.kind, t)}</div>
        <div className="df-preview-stats">
          {t('designFiles.modified', {
            time: relativeTime(file.mtime, t),
            size: humanBytes(file.size),
          })}
        </div>
        <div className="df-preview-actions">
          <a
            className="ghost-link"
            href={url}
            download={file.name}
            style={{ textDecoration: 'none' }}
          >
            {t('designFiles.download')}
          </a>
          <button type="button" onClick={onClose}>
            {t('designFiles.previewClose')}
          </button>
        </div>
      </div>
    </aside>
  );
}

function sectionFor(file: ProjectFile): Section {
  if (file.kind === 'html' || file.kind === 'text') return 'pages';
  if (file.kind === 'sketch') return 'sketches';
  if (file.kind === 'code') return 'scripts';
  if (file.kind === 'image') return 'images';
  return 'other';
}

function kindGlyph(kind: ProjectFileKind): string {
  if (kind === 'html') return '⟨⟩';
  if (kind === 'image') return '▣';
  if (kind === 'sketch') return '✎';
  if (kind === 'text') return '¶';
  if (kind === 'code') return '{}';
  return '·';
}

function kindLabel(kind: ProjectFileKind, t: TranslateFn): string {
  if (kind === 'html') return t('designFiles.kindHtml');
  if (kind === 'image') return t('designFiles.kindImage');
  if (kind === 'sketch') return t('designFiles.kindSketch');
  if (kind === 'text') return t('designFiles.kindText');
  if (kind === 'code') return t('designFiles.kindCode');
  return t('designFiles.kindBinary');
}

function relativeTime(ts: number, t: TranslateFn): string {
  const diff = Date.now() - ts;
  const min = 60_000;
  const hr = 60 * min;
  const day = 24 * hr;
  if (diff < min) return t('common.justNow');
  if (diff < hr) return t('common.minutesAgo', { n: Math.floor(diff / min) });
  if (diff < day) return t('common.hoursAgo', { n: Math.floor(diff / hr) });
  if (diff < 7 * day) return t('common.daysAgo', { n: Math.floor(diff / day) });
  if (diff < 30 * day)
    return t('designFiles.weeksAgo', { n: Math.floor(diff / (7 * day)) });
  return new Date(ts).toLocaleDateString();
}

function humanBytes(n: number): string {
  if (n < 1024) return `${n} B`;
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
  return `${(n / 1024 / 1024).toFixed(1)} MB`;
}
