import { useState, useCallback } from "react";
import { ChevronRight, ChevronDown, FileCode, FileJson, FileText, File, Folder, FolderOpen, FileType } from "lucide-react";
import { invoke } from "@tauri-apps/api/core";
import { cn } from "@/lib/utils";
import { actions } from "@/lib/store";
import { detectLanguage } from "@/lib/languageDetect";
import {
  ContextMenu,
  ContextMenuTrigger,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuSeparator,
} from "@/components/ui/context-menu";

interface DirEntry {
  name: string;
  path: string;
  is_dir: boolean;
}

interface FileTreeNodeProps {
  entry: DirEntry;
  depth: number;
  filter?: string;
  onRefresh: () => void;
}

function getFileIcon(name: string) {
  const ext = name.split(".").pop()?.toLowerCase();
  switch (ext) {
    case "js":
    case "jsx":
    case "ts":
    case "tsx":
    case "py":
    case "rs":
    case "go":
    case "java":
    case "cpp":
    case "c":
    case "h":
    case "php":
      return <FileCode className="h-4 w-4 shrink-0 text-muted-foreground" />;
    case "json":
    case "jsonc":
      return <FileJson className="h-4 w-4 shrink-0 text-yellow-500/70" />;
    case "md":
    case "txt":
    case "markdown":
      return <FileText className="h-4 w-4 shrink-0 text-muted-foreground" />;
    case "html":
    case "htm":
    case "css":
    case "scss":
      return <FileType className="h-4 w-4 shrink-0 text-orange-400/70" />;
    default:
      return <File className="h-4 w-4 shrink-0 text-muted-foreground" />;
  }
}

export function FileTreeNode({ entry, depth, filter, onRefresh }: FileTreeNodeProps) {
  // If filter is active and this is a file that doesn't match, hide it
  const filterLower = filter?.toLowerCase() ?? "";
  const matchesFilter = !filterLower || entry.name.toLowerCase().includes(filterLower);

  // Directories are always shown when filter is active (children might match)
  // Files are hidden if they don't match
  if (filterLower && !entry.is_dir && !matchesFilter) {
    return null;
  }

  const [expanded, setExpanded] = useState(false);
  const [children, setChildren] = useState<DirEntry[]>([]);
  const [loading, setLoading] = useState(false);
  const [renaming, setRenaming] = useState(false);
  const [renameValue, setRenameValue] = useState(entry.name);

  const toggle = useCallback(async () => {
    if (!entry.is_dir) return;
    if (!expanded) {
      setLoading(true);
      try {
        const entries = await invoke<DirEntry[]>("read_directory", { path: entry.path });
        setChildren(entries);
      } catch (err) {
        console.error("Failed to read directory:", err);
      }
      setLoading(false);
    }
    setExpanded(!expanded);
  }, [expanded, entry.is_dir, entry.path]);

  const refreshChildren = useCallback(async () => {
    if (entry.is_dir && expanded) {
      try {
        const entries = await invoke<DirEntry[]>("read_directory", { path: entry.path });
        setChildren(entries);
      } catch (err) {
        console.error("Failed to refresh:", err);
      }
    }
  }, [entry.is_dir, entry.path, expanded]);

  const handleClick = useCallback(async () => {
    if (entry.is_dir) {
      toggle();
      return;
    }
    try {
      const content = await invoke<string>("read_file", { path: entry.path });
      const language = detectLanguage(entry.name);
      actions.openFile(entry.path, entry.name, content, language);
    } catch (err) {
      console.error("Failed to open file:", err);
    }
  }, [entry, toggle]);

  const handleNewFile = useCallback(async () => {
    const name = prompt("File name:");
    if (!name) return;
    try {
      await invoke("create_file", { path: entry.path + "/" + name });
      await refreshChildren();
      if (!expanded) setExpanded(true);
      onRefresh();
    } catch (err) {
      console.error("Failed to create file:", err);
    }
  }, [entry.path, expanded, refreshChildren, onRefresh]);

  const handleNewFolder = useCallback(async () => {
    const name = prompt("Folder name:");
    if (!name) return;
    try {
      await invoke("create_directory", { path: entry.path + "/" + name });
      await refreshChildren();
      if (!expanded) setExpanded(true);
      onRefresh();
    } catch (err) {
      console.error("Failed to create folder:", err);
    }
  }, [entry.path, expanded, refreshChildren, onRefresh]);

  const handleRename = useCallback(async () => {
    if (renameValue === entry.name || !renameValue.trim()) {
      setRenaming(false);
      return;
    }
    const parentPath = entry.path.substring(0, entry.path.lastIndexOf("/"));
    try {
      await invoke("rename_path", {
        oldPath: entry.path,
        newPath: parentPath + "/" + renameValue,
      });
      onRefresh();
    } catch (err) {
      console.error("Failed to rename:", err);
    }
    setRenaming(false);
  }, [renameValue, entry, onRefresh]);

  const handleDelete = useCallback(async () => {
    if (!confirm(`Delete "${entry.name}"?`)) return;
    try {
      await invoke("delete_path", { path: entry.path });
      onRefresh();
    } catch (err) {
      console.error("Failed to delete:", err);
    }
  }, [entry, onRefresh]);

  return (
    <div>
      <ContextMenu>
        <ContextMenuTrigger asChild>
          <div
            className={cn(
              "flex items-center h-[22px] cursor-pointer hover:bg-[#2a2d2e] select-none",
              "text-sm text-sidebar-foreground"
            )}
            style={{ paddingLeft: depth * 12 + 4 }}
            onClick={handleClick}
          >
            {entry.is_dir ? (
              <>
                {expanded ? (
                  <ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground" />
                ) : (
                  <ChevronRight className="h-4 w-4 shrink-0 text-muted-foreground" />
                )}
                {expanded ? (
                  <FolderOpen className="h-4 w-4 shrink-0 ml-0.5 text-yellow-500/70" />
                ) : (
                  <Folder className="h-4 w-4 shrink-0 ml-0.5 text-yellow-500/70" />
                )}
              </>
            ) : (
              <>
                <span className="w-4 shrink-0" />
                {getFileIcon(entry.name)}
              </>
            )}
            {renaming ? (
              <input
                className="ml-1 flex-1 bg-[#3c3c3c] text-foreground text-sm px-1 py-0 border border-[#007acc] outline-none rounded-sm"
                value={renameValue}
                onChange={(e) => setRenameValue(e.target.value)}
                onBlur={handleRename}
                onKeyDown={(e) => {
                  if (e.key === "Enter") handleRename();
                  if (e.key === "Escape") setRenaming(false);
                }}
                autoFocus
                onClick={(e) => e.stopPropagation()}
              />
            ) : (
              <span className="ml-1 truncate">{entry.name}</span>
            )}
            {loading && <span className="ml-1 text-xs text-muted-foreground">...</span>}
          </div>
        </ContextMenuTrigger>
        <ContextMenuContent>
          {entry.is_dir && (
            <>
              <ContextMenuItem onClick={handleNewFile}>New File</ContextMenuItem>
              <ContextMenuItem onClick={handleNewFolder}>New Folder</ContextMenuItem>
              <ContextMenuSeparator />
            </>
          )}
          <ContextMenuItem
            onClick={() => {
              setRenameValue(entry.name);
              setRenaming(true);
            }}
          >
            Rename
          </ContextMenuItem>
          <ContextMenuItem className="text-destructive focus:text-destructive" onClick={handleDelete}>
            Delete
          </ContextMenuItem>
        </ContextMenuContent>
      </ContextMenu>

      {entry.is_dir && (expanded || !!filterLower) && (
        <div>
          {children.map((child) => (
            <FileTreeNode
              key={child.path}
              entry={child}
              depth={depth + 1}
              filter={filter}
              onRefresh={refreshChildren}
            />
          ))}
        </div>
      )}
    </div>
  );
}
