import { useState, useEffect, useCallback } from "react";
import { Command } from "cmdk";
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
import { invoke } from "@tauri-apps/api/core";
import { actions, useStore } from "@/lib/store";
import { detectLanguage } from "@/lib/languageDetect";
import { FileCode } from "lucide-react";

interface QuickOpenProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
}

interface FileEntry {
  name: string;
  path: string;
  relative: string;
}

async function collectFiles(dir: string, base: string, result: FileEntry[], depth: number) {
  if (depth > 5) return;
  try {
    const entries = await invoke<{ name: string; path: string; is_dir: boolean }[]>("read_directory", { path: dir });
    for (const entry of entries) {
      const relative = base ? base + "/" + entry.name : entry.name;
      if (entry.is_dir) {
        if (entry.name === "node_modules" || entry.name === "target" || entry.name === ".git" || entry.name === "dist") continue;
        await collectFiles(entry.path, relative, result, depth + 1);
      } else {
        result.push({ name: entry.name, path: entry.path, relative });
      }
    }
  } catch {
    // skip inaccessible dirs
  }
}

export function QuickOpen({ open: isOpen, onOpenChange }: QuickOpenProps) {
  const { workspacePath } = useStore();
  const [files, setFiles] = useState<FileEntry[]>([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    if (isOpen && workspacePath) {
      setLoading(true);
      const result: FileEntry[] = [];
      collectFiles(workspacePath, "", result, 0).then(() => {
        setFiles(result);
        setLoading(false);
      });
    }
  }, [isOpen, workspacePath]);

  const handleSelect = useCallback(
    async (filePath: string, fileName: string) => {
      try {
        const content = await invoke<string>("read_file", { path: filePath });
        const language = detectLanguage(fileName);
        actions.openFile(filePath, fileName, content, language);
      } catch (err) {
        console.error("Failed to open file:", err);
      }
      onOpenChange(false);
    },
    [onOpenChange]
  );

  return (
    <Dialog open={isOpen} onOpenChange={onOpenChange}>
      <DialogContent className="p-0 gap-0 max-w-[500px] overflow-hidden border-border">
        <VisuallyHidden>
          <DialogTitle>Quick Open</DialogTitle>
        </VisuallyHidden>
        <Command className="bg-card" loop>
          <Command.Input
            placeholder="Search files..."
            className="h-10 w-full border-b border-border bg-transparent px-3 text-sm text-foreground outline-none placeholder:text-muted-foreground"
          />
          <Command.List className="max-h-[300px] overflow-y-auto p-1">
            {loading ? (
              <div className="py-6 text-center text-sm text-muted-foreground">Loading...</div>
            ) : (
              <>
                <Command.Empty className="py-6 text-center text-sm text-muted-foreground">
                  No files found.
                </Command.Empty>
                {files.map((file) => (
                  <Command.Item
                    key={file.path}
                    value={file.relative}
                    className="flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm text-foreground outline-none transition-colors aria-selected:bg-accent aria-selected:text-accent-foreground"
                    onSelect={() => handleSelect(file.path, file.name)}
                  >
                    <FileCode className="h-4 w-4 shrink-0 text-muted-foreground" />
                    <div className="flex flex-col min-w-0">
                      <span className="truncate">{file.name}</span>
                      <span className="truncate text-xs text-muted-foreground">{file.relative}</span>
                    </div>
                  </Command.Item>
                ))}
              </>
            )}
          </Command.List>
        </Command>
      </DialogContent>
    </Dialog>
  );
}
