import { useState } from 'react';
import { Link } from 'react-router';
import { ChevronRight, ChevronDown, Folder } from 'lucide-react';
import { getIcon } from 'material-file-icons';
import { useFilesAPI, type DirEntry } from '../../hooks/useFilesAPI';

/**
 * `searchForFile` turns file rows into real links when the editor owns the address bar. Folder rows stay
 * buttons on purpose: expanding a directory is disclosure, not navigation — it opens nothing, it changes
 * no selection, and there would be nothing for a new tab to show.
 */
type FileTreeProps = {
  root: string;
  basePath: string;
  onOpenFile: (path: string, name: string) => void;
  searchForFile?: ((path: string) => string) | null;
};

type TreeNodeProps = {
  entry: DirEntry;
  parentPath: string;
  root: string;
  onOpenFile: (path: string, name: string) => void;
  searchForFile?: ((path: string) => string) | null;
  depth: number;
};

const FileIcon = ({ name }: { name: string }) => {
  const svg = getIcon(name).svg;
  return <span className="inline-flex h-4 w-4 shrink-0" dangerouslySetInnerHTML={{ __html: svg }} />;
};

const sortEntries = (entries: DirEntry[]) => {
  const dirs = entries.filter((e) => e.type === 'directory').sort((a, b) => a.name.localeCompare(b.name));
  const files = entries.filter((e) => e.type === 'file').sort((a, b) => a.name.localeCompare(b.name));
  return [...dirs, ...files];
};

const TreeNode = ({ entry, parentPath, root, onOpenFile, searchForFile, depth }: TreeNodeProps) => {
  const [expanded, setExpanded] = useState(false);
  const [children, setChildren] = useState<DirEntry[] | null>(null);
  const [loading, setLoading] = useState(false);
  const { listDir } = useFilesAPI(root);
  const isDir = entry.type === 'directory';
  const fullPath = parentPath === '/' ? `/${entry.name}` : `${parentPath}/${entry.name}`;

  const handleClick = async () => {
    if (!isDir) {
      onOpenFile(fullPath, entry.name);
      return;
    }
    if (!expanded && children === null) {
      setLoading(true);
      try {
        const res = await listDir(fullPath);
        setChildren(sortEntries(res.entries));
      } catch {
        setChildren([]);
      }
      setLoading(false);
    }
    setExpanded((prev) => !prev);
  };

  const rowClass =
    'flex items-center gap-1 w-full px-1 py-0.5 text-sm rounded cursor-pointer transition-colors text-left text-[#ccc] hover:bg-white/5';
  const rowStyle = { paddingLeft: `${depth * 12 + 4}px` };

  const body = (
    <>
      {isDir ? (
        <>
          {expanded ? (
            <ChevronDown className="h-3.5 w-3.5 shrink-0 text-[#888]" />
          ) : (
            <ChevronRight className="h-3.5 w-3.5 shrink-0 text-[#888]" />
          )}
          <Folder className="h-4 w-4 shrink-0 text-duck-yellow fill-duck-yellow/30" />
        </>
      ) : (
        <>
          <span className="w-3.5 shrink-0" />
          <FileIcon name={entry.name} />
        </>
      )}
      <span className="truncate">{entry.name}</span>
      {loading && <span className="text-xs text-[#888] ml-auto">...</span>}
    </>
  );

  return (
    <div>
      {!isDir && searchForFile ? (
        <Link to={{ search: searchForFile(fullPath) }} className={rowClass} style={rowStyle}>
          {body}
        </Link>
      ) : (
        <button onClick={handleClick} className={rowClass} style={rowStyle}>
          {body}
        </button>
      )}
      {isDir && expanded && children && (
        <div>
          {children.map((child) => (
            <TreeNode
              key={child.name}
              entry={child}
              parentPath={fullPath}
              root={root}
              onOpenFile={onOpenFile}
              searchForFile={searchForFile}
              depth={depth + 1}
            />
          ))}
        </div>
      )}
    </div>
  );
};

export const FileTree = ({ root, basePath, onOpenFile, searchForFile }: FileTreeProps) => {
  const { listDir } = useFilesAPI(root);
  const [entries, setEntries] = useState<DirEntry[] | null>(null);
  const [loading, setLoading] = useState(false);

  const loadRoot = async () => {
    setLoading(true);
    try {
      const res = await listDir(basePath);
      setEntries(sortEntries(res.entries));
    } catch {
      setEntries([]);
    }
    setLoading(false);
  };

  if (entries === null && !loading) {
    loadRoot();
  }

  if (loading && entries === null) {
    return <div className="p-2 text-sm text-[#888]">Loading...</div>;
  }

  if (!entries || entries.length === 0) {
    return <div className="p-2 text-sm text-[#888]">No files</div>;
  }

  return (
    <div className="py-1 overflow-y-auto h-full code-editor-scrollable">
      {entries.map((entry) => (
        <TreeNode
          key={entry.name}
          entry={entry}
          parentPath={basePath}
          root={root}
          onOpenFile={onOpenFile}
          searchForFile={searchForFile}
          depth={0}
        />
      ))}
    </div>
  );
};
