import { useEffect, useRef, useState } from 'react';
import { listDocuments, type DocumentFile } from '../api/client';

interface FileExplorerProps {
  onSelectFile: (key: string) => void;
  selectedKey?: string | null;
  refreshKey?: number;
}

export default function FileExplorer({ onSelectFile, selectedKey, refreshKey }: FileExplorerProps) {
  const [folders, setFolders] = useState<string[]>([]);
  const [files, setFiles] = useState<DocumentFile[]>([]);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    listDocuments('')
      .then((data) => {
        setFolders(data.folders);
        setFiles(data.files);
      })
      .catch(() => setError('无法加载文档目录'));
  }, [refreshKey]);

  if (error) {
    return <div data-testid="file-explorer-error">{error}</div>;
  }

  return (
    <div data-testid="file-explorer">
      {folders.map((folder) => (
        <FolderNode key={folder} name={folder} path={folder} onSelectFile={onSelectFile} selectedKey={selectedKey} />
      ))}
      {files.map((file) => (
        <FileRow key={file.key} file={file} onSelectFile={onSelectFile} selectedKey={selectedKey} />
      ))}
    </div>
  );
}

function SidebarLabel({ text }: { text: string }) {
  const ref = useRef<HTMLSpanElement>(null);
  const [overflows, setOverflows] = useState(false);

  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const check = () => setOverflows(el.scrollWidth > el.clientWidth);
    check();
    const ro = new ResizeObserver(check);
    ro.observe(el);
    return () => ro.disconnect();
  }, [text]);

  return (
    <span className={overflows ? 'sidebar-label has-tip' : 'sidebar-label'} data-tip={text}>
      <span ref={ref} className="label-text">{text}</span>
    </span>
  );
}

function FileRow({
  file,
  onSelectFile,
  selectedKey,
}: {
  file: DocumentFile;
  onSelectFile: (key: string) => void;
  selectedKey?: string | null;
}) {
  return (
    <div
      data-testid={`file-${file.key}`}
      className={selectedKey === file.key ? 'tree-item file-row active' : 'tree-item file-row'}
      onClick={() => onSelectFile(file.key)}
    >
      <svg className="file-icon" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
        <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" />
        <path d="M14 2v6h6" />
      </svg>
      <SidebarLabel text={file.name} />
    </div>
  );
}

function FolderNode({
  name,
  path,
  onSelectFile,
  selectedKey,
}: {
  name: string;
  path: string;
  onSelectFile: (key: string) => void;
  selectedKey?: string | null;
}) {
  const [expanded, setExpanded] = useState(false);
  const [loaded, setLoaded] = useState(false);
  const [folders, setFolders] = useState<string[]>([]);
  const [files, setFiles] = useState<DocumentFile[]>([]);

  function toggle() {
    if (!expanded && !loaded) {
      listDocuments(path).then((data) => {
        setFolders(data.folders);
        setFiles(data.files);
        setLoaded(true);
      });
    }
    setExpanded((prev) => !prev);
  }

  return (
    <div>
      <div data-testid={`folder-${path}`} className="tree-item folder" onClick={toggle}>
        <span className={expanded ? 'chevron open' : 'chevron'}>
          <svg width="10" height="10" viewBox="0 0 24 24" fill="currentColor">
            <path d="M8 5v14l11-7z" />
          </svg>
        </span>
        <SidebarLabel text={name} />
      </div>
      {expanded && (
        <div className="tree-children">
          {folders.map((folder) => (
            <FolderNode
              key={`${path}/${folder}`}
              name={folder}
              path={`${path}/${folder}`}
              onSelectFile={onSelectFile}
              selectedKey={selectedKey}
            />
          ))}
          {files.map((file) => (
            <FileRow key={file.key} file={file} onSelectFile={onSelectFile} selectedKey={selectedKey} />
          ))}
        </div>
      )}
    </div>
  );
}
