import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { Folder, ChevronRight, Loader2, FolderPlus, Check, Eye, EyeOff } from 'lucide-react';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { useFilesAPI, type DirEntry } from '../../hooks/useFilesAPI';

type DirPickerModalProps = {
  open: boolean;
  onClose: () => void;
  onSelect: (absPath: string) => void;
};

// A simplified file-browser modal for picking a working directory (returns an absolute path).
// Navigates within the home root; dirs elsewhere are reachable via the selector's free-text field.
export const DirPickerModal = ({ open, onClose, onSelect }: DirPickerModalProps) => {
  const api = useFilesAPI('home');
  const [path, setPath] = useState('/'); // root-relative, always starts with '/'
  const [creating, setCreating] = useState(false);
  const [newName, setNewName] = useState('');
  // Off by default. The server does not filter these — `readdir` returns everything — so a home
  // directory opened straight onto `.cache`, `.local`, `.npm` and thirty more before anything you
  // recognise. They are still reachable, just not in the way by default.
  const [showHidden, setShowHidden] = useState(false);

  const { data, isLoading, refetch } = useQuery({
    queryKey: ['dir-picker', path],
    queryFn: () => api.listDir(path),
    enabled: open,
  });

  const rootDir = data?.rootDir ?? '';
  const allDirs = ((data?.entries ?? []) as DirEntry[])
    .filter((e) => e.type === 'directory')
    .sort((a, b) => a.name.localeCompare(b.name));
  const hiddenCount = allDirs.filter((d) => d.name.startsWith('.')).length;
  const dirs = showHidden ? allDirs : allDirs.filter((d) => !d.name.startsWith('.'));
  const absCurrent = path === '/' ? rootDir : `${rootDir}${path}`;

  const segments = path.split('/').filter(Boolean);
  const goto = (idx: number) => setPath(idx < 0 ? '/' : `/${segments.slice(0, idx + 1).join('/')}`);
  const enter = (name: string) => setPath(path === '/' ? `/${name}` : `${path}/${name}`);

  const createFolder = async () => {
    const n = newName.trim();
    if (!n) return;
    await api.createDir(path === '/' ? `/${n}` : `${path}/${n}`);
    setNewName('');
    setCreating(false);
    refetch();
  };

  return (
    <Dialog open={open} onOpenChange={(o) => !o && onClose()}>
      <DialogContent className="flex h-[70vh] max-w-2xl flex-col gap-0 p-0">
        <DialogHeader className="border-b border-border px-4 py-3">
          <DialogTitle className="text-sm">Choose a working directory</DialogTitle>
        </DialogHeader>

        {/* Breadcrumb */}
        <div className="flex flex-wrap items-center gap-1 border-b border-border px-4 py-2 text-xs text-muted-foreground">
          <button onClick={() => goto(-1)} className="hover:text-duck-teal cursor-pointer">
            ~
          </button>
          {segments.map((s, i) => (
            <span key={i} className="flex items-center gap-1">
              <ChevronRight className="h-3 w-3 opacity-40" />
              <button onClick={() => goto(i)} className="hover:text-duck-teal cursor-pointer">
                {s}
              </button>
            </span>
          ))}
        </div>

        {/* Directory list */}
        <div className="min-h-0 flex-1 overflow-y-auto p-2">
          {isLoading ? (
            <div className="flex h-full items-center justify-center opacity-50">
              <Loader2 className="h-5 w-5 animate-spin" />
            </div>
          ) : dirs.length === 0 ? (
            // Say when the folder isn't actually empty, just filtered — "No subfolders here" over a
            // directory holding thirty dot-folders is a lie the toggle below can't help you spot.
            <div className="flex h-full items-center justify-center px-4 text-center text-sm opacity-40">
              {hiddenCount > 0
                ? `No visible subfolders — ${hiddenCount} hidden ${hiddenCount === 1 ? 'one is' : 'ones are'} filtered out`
                : 'No subfolders here'}
            </div>
          ) : (
            dirs.map((d) => (
              <button
                key={d.name}
                onClick={() => enter(d.name)}
                className="flex w-full items-center gap-2 rounded px-3 py-2 text-left text-sm hover:bg-accent cursor-pointer"
              >
                <Folder
                  className={`h-4 w-4 shrink-0 text-duck-teal/70 ${d.name.startsWith('.') ? 'opacity-50' : ''}`}
                />
                <span className={`truncate ${d.name.startsWith('.') ? 'opacity-60' : ''}`}>{d.name}</span>
              </button>
            ))
          )}
        </div>

        {/* Footer */}
        <div className="flex flex-col gap-2 border-t border-border px-4 py-3">
          {creating ? (
            <div className="flex items-center gap-1">
              <input
                autoFocus
                value={newName}
                onChange={(ev) => setNewName(ev.target.value)}
                onKeyDown={(ev) => {
                  if (ev.key === 'Enter') createFolder();
                  if (ev.key === 'Escape') setCreating(false);
                }}
                placeholder="New folder name"
                className="min-w-0 flex-1 rounded border border-border bg-transparent px-2 py-1 text-xs outline-none"
              />
              <button
                onClick={createFolder}
                className="rounded px-2 py-1 text-xs text-duck-teal hover:bg-duck-teal/10 cursor-pointer"
              >
                Create
              </button>
            </div>
          ) : (
            <div className="flex items-center justify-between gap-2">
              <button
                onClick={() => setCreating(true)}
                className="flex items-center gap-1.5 text-xs opacity-60 hover:opacity-100 cursor-pointer"
              >
                <FolderPlus className="h-3.5 w-3.5" /> New folder
              </button>
              {/* Shown even at zero, so the control's state is always legible: a folder with nothing
                  hidden and one with everything hidden must not look identical. */}
              <button
                onClick={() => setShowHidden((prev) => !prev)}
                title={showHidden ? 'Hide dot-directories' : 'Show dot-directories'}
                className="flex items-center gap-1.5 text-xs opacity-60 hover:opacity-100 cursor-pointer"
              >
                {showHidden ? <EyeOff className="h-3.5 w-3.5" /> : <Eye className="h-3.5 w-3.5" />}
                {showHidden ? 'Hide hidden' : `Show hidden${hiddenCount > 0 ? ` (${hiddenCount})` : ''}`}
              </button>
            </div>
          )}
          <div className="flex items-center gap-2">
            <span className="min-w-0 flex-1 truncate text-xs opacity-60" title={absCurrent}>
              {absCurrent}
            </span>
            <button
              onClick={onClose}
              className="rounded-md px-3 py-1.5 text-sm opacity-60 hover:opacity-100 cursor-pointer"
            >
              Cancel
            </button>
            <button
              onClick={() => {
                onSelect(absCurrent);
                onClose();
              }}
              disabled={!absCurrent}
              className="flex items-center gap-1.5 rounded-md bg-duck-teal px-3 py-1.5 text-sm font-medium text-duck-yellow hover:bg-duck-teal/90 disabled:opacity-50 cursor-pointer"
            >
              <Check className="h-3.5 w-3.5" /> Select this folder
            </button>
          </div>
        </div>
      </DialogContent>
    </Dialog>
  );
};
