import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { toast } from "sonner";
import { MoreVertical, Plus, FolderPlus, ChevronRight, Folder, FileText, KeyRound, ArrowLeft, ArrowUp, ArrowDown } from "lucide-react";
import { usePagesStore } from "@/stores/pagesStore";
import * as api from "@/api/client";
import StatusBadge from "@/components/dashboard/StatusBadge";
import { Button } from "@/components/ui/button";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import {
  Popover,
  PopoverTrigger,
  PopoverContent,
} from "@/components/ui/popover";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { useWindowManager } from "@/hooks/useWindowManager";
import EditorWindow, { type EditorWinData } from "@/components/editor/EditorWindow";
import EditorPane from "@/components/editor/EditorPane";
import EditorPointer from "@/components/editor/EditorPointer";
import FloatingWindow from "@/components/shared/FloatingWindow";
import type { ManagedWindow } from "@/hooks/useWindowManager";

// ---------------------------------------------------------------------------
// Env editor window data
// ---------------------------------------------------------------------------

interface EnvWinData {
  kind: "env";
}

// ---------------------------------------------------------------------------
// Main component
// ---------------------------------------------------------------------------

export default function ComposeView() {
  const { deletePage, publishPage, unpublishPage } = usePagesStore();

  // File browser state
  const [currentPath, setCurrentPath] = useState("");
  const [files, setFiles] = useState<api.FileEntry[]>([]);
  const [isLoading, setIsLoading] = useState(false);
  const [pageToDelete, setPageToDelete] = useState<string | null>(null);
  const [newFolderName, setNewFolderName] = useState("");
  const [showNewFolder, setShowNewFolder] = useState(false);
  const [sortKey, setSortKey] = useState<"name" | "size" | "modified">("name");
  const [sortAsc, setSortAsc] = useState(true);

  const sortedFiles = useMemo(() => {
    // Folders always first, then sort within each group
    const folders = files.filter(f => f.type === "folder");
    const rest = files.filter(f => f.type !== "folder");
    const cmp = (a: api.FileEntry, b: api.FileEntry): number => {
      let v = 0;
      if (sortKey === "name") v = a.name.localeCompare(b.name);
      else if (sortKey === "size") v = (a.size ?? 0) - (b.size ?? 0);
      else if (sortKey === "modified") v = (a.last_modified ?? 0) - (b.last_modified ?? 0);
      return sortAsc ? v : -v;
    };
    folders.sort(cmp);
    rest.sort(cmp);
    return [...folders, ...rest];
  }, [files, sortKey, sortAsc]);

  const toggleSort = (key: "name" | "size" | "modified") => {
    if (sortKey === key) setSortAsc(!sortAsc);
    else { setSortKey(key); setSortAsc(true); }
  };

  // Editor windows
  const { windows: editorWindows, focusedId: editorFocused, open: openEditorWin, update: updateEditorWin, close: closeEditorWin, focus: focusEditorWin } = useWindowManager<EditorWinData>({ w: 720, h: 520 });

  // Env editor windows
  const { windows: envWindows, focusedId: envFocused, open: openEnvWin, update: updateEnvWin, close: closeEnvWin, focus: focusEnvWin } = useWindowManager<EnvWinData>({ w: 520, h: 400 });

  const loadFiles = useCallback(async (path: string = currentPath) => {
    setIsLoading(true);
    try {
      const entries = await api.fetchFiles(path);
      setFiles(entries);
    } finally {
      setIsLoading(false);
    }
  }, [currentPath]);

  useEffect(() => { loadFiles(currentPath); }, [currentPath]);

  const navigateTo = (path: string) => setCurrentPath(path);

  const navigateUp = () => {
    if (!currentPath) return;
    const parts = currentPath.split("/").filter(Boolean);
    parts.pop();
    setCurrentPath(parts.join("/"));
  };

  // Path breadcrumbs
  const pathParts = currentPath ? currentPath.split("/").filter(Boolean) : [];

  const openEditor = (name: string, isNew: boolean) => {
    // For files in subfolders, use full relative path as page name
    const pageName = isNew ? "" : name;
    const id = isNew ? `new-${Date.now()}` : pageName;
    openEditorWin(id, { pageName, isNew });
  };

  const openEnvEditor = () => {
    openEnvWin("env-editor", { kind: "env" });
  };


  const handlePublish = async (name: string) => {
    try {
      await publishPage(name);
      toast.success(`"${name}" published`);
      loadFiles();
    } catch (e) {
      toast.error(`Failed: ${e}`);
    }
  };

  const handleUnpublish = async (name: string) => {
    try {
      await unpublishPage(name);
      toast.success(`"${name}" unpublished`);
      loadFiles();
    } catch (e) {
      toast.error(`Failed: ${e}`);
    }
  };

  const handleDelete = async () => {
    if (!pageToDelete) return;
    // Extract stem from path for the pages API
    const stem = pageToDelete.replace(/\.uf$/, "");
    await deletePage(stem);
    toast.success(`"${pageToDelete}" deleted`);
    setPageToDelete(null);
    loadFiles();
  };

  const handleCreateFolder = async () => {
    const name = newFolderName.trim();
    if (!name) return;
    const folderPath = currentPath ? `${currentPath}/${name}` : name;
    try {
      await api.createFolder(folderPath);
      toast.success(`Folder "${name}" created`);
      setNewFolderName("");
      setShowNewFolder(false);
      loadFiles();
    } catch (e) {
      toast.error(`Failed: ${e}`);
    }
  };

  const handleFileClick = (entry: api.FileEntry) => {
    if (entry.type === "folder") {
      navigateTo(entry.path);
    } else if (entry.type === "env") {
      openEnvEditor();
    } else {
      // Open .uf file in editor — strip .uf extension for page name
      const pageName = entry.path.replace(/\.uf$/, "");
      openEditor(pageName, false);
    }
  };

  const formatSize = (size: number | null) => {
    if (size == null) return "\u2014";
    if (size < 1024) return `${size} B`;
    return `${(size / 1024).toFixed(1)} KB`;
  };

  const formatTime = (ts: number | null) => {
    if (ts == null) return "\u2014";
    const d = new Date(ts * 1000);
    return d.toLocaleDateString(undefined, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
  };

  return (
    <div className="flex flex-col h-full">
      <div className="flex flex-col flex-1 min-h-0">
        {/* Header row */}
        <div className="flex items-center px-2 py-1.5 border-b-2 border-border">
          <h1 className="text-xs font-semibold flex-1">Compose</h1>
          <div className="flex gap-2">
<Button variant="outline" size="sm" onClick={() => setShowNewFolder(true)}>
              <FolderPlus className="w-3 h-3 mr-1.5" />
              New Folder
            </Button>
            <Button size="sm" onClick={() => openEditor("", true)}>
              <Plus className="w-3 h-3 mr-1.5" />
              New Page
            </Button>
          </div>
        </div>

        {/* Path bar */}
        <div className="flex items-center px-3 py-1.5 border-b border-border bg-muted/15 text-xs">
          {currentPath && (
            <button onClick={navigateUp} className="mr-2 text-muted-foreground hover:text-foreground transition-colors cursor-pointer">
              <ArrowLeft className="w-3.5 h-3.5" />
            </button>
          )}
          <button onClick={() => navigateTo("")} className="text-muted-foreground hover:text-foreground transition-colors cursor-pointer font-mono">
            /
          </button>
          {pathParts.map((part, i) => {
            const partPath = pathParts.slice(0, i + 1).join("/");
            return (
              <span key={partPath} className="flex items-center">
                <ChevronRight className="w-3 h-3 mx-0.5 text-muted-foreground/50" />
                <button onClick={() => navigateTo(partPath)} className="text-muted-foreground hover:text-foreground transition-colors cursor-pointer font-mono">
                  {part}
                </button>
              </span>
            );
          })}

          {/* New folder inline input */}
          {showNewFolder && (
            <span className="flex items-center ml-4 gap-1">
              <ChevronRight className="w-3 h-3 text-muted-foreground/50" />
              <input
                autoFocus
                value={newFolderName}
                onChange={(e) => setNewFolderName(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key === "Enter") handleCreateFolder();
                  if (e.key === "Escape") { setShowNewFolder(false); setNewFolderName(""); }
                }}
                placeholder="folder name"
                className="h-5 px-1.5 text-xs bg-background border border-border rounded font-mono w-32 focus:outline-none focus:ring-1 focus:ring-primary"
              />
              <button onClick={handleCreateFolder} className="text-primary text-xs cursor-pointer">create</button>
              <button onClick={() => { setShowNewFolder(false); setNewFolderName(""); }} className="text-muted-foreground text-xs cursor-pointer">cancel</button>
            </span>
          )}
        </div>

        {/* File table */}
        <div className="flex-1 min-h-0 overflow-auto">
        {isLoading ? (
          <div className="flex items-center justify-center h-32 text-muted-foreground text-sm">Loading...</div>
        ) : (
          <Table>
            <TableHeader>
              <TableRow>
                <SortableHead label="Name" sortKey="name" currentKey={sortKey} asc={sortAsc} onToggle={toggleSort} />
                <TableHead>Status</TableHead>
                <SortableHead label="Size" sortKey="size" currentKey={sortKey} asc={sortAsc} onToggle={toggleSort} />
                <SortableHead label="Modified" sortKey="modified" currentKey={sortKey} asc={sortAsc} onToggle={toggleSort} />
                <TableHead className="w-8" />
              </TableRow>
            </TableHeader>
            <TableBody>
              {sortedFiles.map((entry) => (
                <TableRow
                  key={entry.path}
                  className="cursor-pointer"
                  onClick={() => handleFileClick(entry)}
                >
                  <TableCell className="font-mono">
                    <span className="flex items-center gap-2">
                      {entry.type === "folder" ? (
                        <Folder className="w-3.5 h-3.5 text-primary/70 shrink-0" />
                      ) : entry.type === "env" ? (
                        <KeyRound className="w-3.5 h-3.5 text-amber-500/70 shrink-0" />
                      ) : (
                        <FileText className="w-3.5 h-3.5 text-muted-foreground/50 shrink-0" />
                      )}
                      <span>{entry.name}</span>
                      {entry.name === "index.uf" && (
                        <span className="text-[10px] text-primary">homepage</span>
                      )}
                    </span>
                  </TableCell>
                  <TableCell>
                    {entry.type === "file" && entry.name.endsWith(".uf") ? (
                      <StatusBadge published={entry.published} hasSource={true} />
                    ) : null}
                  </TableCell>
                  <TableCell className="text-muted-foreground">
                    {entry.type !== "folder" ? formatSize(entry.size) : "\u2014"}
                  </TableCell>
                  <TableCell className="text-muted-foreground text-xs">
                    {formatTime(entry.last_modified)}
                  </TableCell>
                  <TableCell className="text-right w-8">
                    {entry.type === "file" && entry.name.endsWith(".uf") && (
                      <FileActions
                        entry={entry}
                        folders={files.filter(f => f.type === "folder")}
                        currentPath={currentPath}
                        onEdit={() => handleFileClick(entry)}
                        onPublish={() => handlePublish(entry.path.replace(/\.uf$/, ""))}
                        onUnpublish={() => handleUnpublish(entry.path.replace(/\.uf$/, ""))}
                        onDelete={() => setPageToDelete(entry.path)}
                        onMove={async (to) => {
                          try {
                            await api.moveFile(entry.path, to);
                            toast.success(`Moved "${entry.name}" to ${to || "/"}`);
                            loadFiles();
                          } catch (e) {
                            toast.error(`Move failed: ${e}`);
                          }
                        }}
                      />
                    )}
                  </TableCell>
                </TableRow>
              ))}
              {files.length === 0 && (
                <TableRow>
                  <TableCell colSpan={5} className="text-center text-muted-foreground py-8">
                    {currentPath ? "Empty folder." : "No files yet. Create a page to get started."}
                  </TableCell>
                </TableRow>
              )}
            </TableBody>
          </Table>
        )}
        </div>
      </div>

      {/* Delete confirmation */}
      <AlertDialog
        open={pageToDelete !== null}
        onOpenChange={(open) => !open && setPageToDelete(null)}
      >
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>Delete "{pageToDelete}"?</AlertDialogTitle>
            <AlertDialogDescription>
              This permanently deletes the file and its published version. This cannot be undone.
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>Cancel</AlertDialogCancel>
            <AlertDialogAction
              onClick={handleDelete}
              className="bg-destructive text-white hover:bg-destructive/90"
            >
              Delete
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>

      {/* Editor windows */}
      {editorWindows.map((win) => (
        <EditorWindow
          key={win.id}
          win={win}
          focused={editorFocused === win.id}
          onUpdate={updateEditorWin}
          onClose={closeEditorWin}
          onFocus={focusEditorWin}
        />
      ))}

      {/* Env editor windows */}
      {envWindows.map((win) => (
        <EnvEditorWindow
          key={win.id}
          win={win}
          focused={envFocused === win.id}
          onUpdate={updateEnvWin}
          onClose={closeEnvWin}
          onFocus={focusEnvWin}
        />
      ))}
    </div>
  );
}


// ---------------------------------------------------------------------------
// File action menu
// ---------------------------------------------------------------------------

function FileActions({
  entry,
  folders,
  currentPath,
  onEdit,
  onPublish,
  onUnpublish,
  onDelete,
  onMove,
}: {
  entry: api.FileEntry;
  folders: api.FileEntry[];
  currentPath: string;
  onEdit: () => void;
  onPublish: () => void;
  onUnpublish: () => void;
  onDelete: () => void;
  onMove: (to: string) => void;
}) {
  const [showMove, setShowMove] = useState(false);

  // Build move targets: parent dir (if in a subfolder) + sibling folders
  const moveTargets: { label: string; path: string }[] = [];
  if (currentPath) {
    moveTargets.push({ label: "/ (root)", path: entry.name });
  }
  for (const f of folders) {
    moveTargets.push({ label: f.name + "/", path: f.path + "/" + entry.name });
  }

  return (
    <Popover>
      <PopoverTrigger
        render={
          <button
            onClick={(e) => e.stopPropagation()}
            className="p-1 text-muted-foreground hover:text-foreground transition-colors cursor-pointer"
          >
            <MoreVertical className="w-4 h-4" />
          </button>
        }
      />
      <PopoverContent side="bottom" align="end" sideOffset={4} className="w-44 p-1">
        <button
          onClick={(e) => { e.stopPropagation(); onEdit(); }}
          className="w-full text-left px-3 py-1.5 text-xs hover:bg-accent transition-colors cursor-pointer"
        >Edit</button>
        {entry.published ? (
          <button
            onClick={(e) => { e.stopPropagation(); onUnpublish(); }}
            className="w-full text-left px-3 py-1.5 text-xs hover:bg-accent transition-colors cursor-pointer"
          >Unpublish</button>
        ) : (
          <button
            onClick={(e) => { e.stopPropagation(); onPublish(); }}
            className="w-full text-left px-3 py-1.5 text-xs hover:bg-accent transition-colors cursor-pointer"
          >Publish</button>
        )}
        {moveTargets.length > 0 && (
          <>
            <button
              onClick={(e) => { e.stopPropagation(); setShowMove(!showMove); }}
              className="w-full text-left px-3 py-1.5 text-xs hover:bg-accent transition-colors cursor-pointer flex items-center justify-between"
            >
              Move to…
              <ChevronRight className={`w-3 h-3 transition-transform ${showMove ? "rotate-90" : ""}`} />
            </button>
            {showMove && (
              <div className="border-t border-border mt-0.5 pt-0.5">
                {moveTargets.map((t) => (
                  <button
                    key={t.path}
                    onClick={(e) => { e.stopPropagation(); onMove(t.path); }}
                    className="w-full text-left px-4 py-1.5 text-xs font-mono text-muted-foreground hover:text-foreground hover:bg-accent transition-colors cursor-pointer flex items-center gap-1.5"
                  >
                    <Folder className="w-3 h-3 shrink-0" />
                    {t.label}
                  </button>
                ))}
              </div>
            )}
          </>
        )}
        <button
          onClick={(e) => { e.stopPropagation(); onDelete(); }}
          className="w-full text-left px-3 py-1.5 text-xs text-destructive hover:bg-accent transition-colors cursor-pointer"
        >Delete</button>
      </PopoverContent>
    </Popover>
  );
}


// ---------------------------------------------------------------------------
// Sortable table header
// ---------------------------------------------------------------------------

function SortableHead({ label, sortKey, currentKey, asc, onToggle }: {
  label: string;
  sortKey: "name" | "size" | "modified";
  currentKey: string;
  asc: boolean;
  onToggle: (key: "name" | "size" | "modified") => void;
}) {
  const active = currentKey === sortKey;
  return (
    <TableHead>
      <button
        onClick={(e) => { e.stopPropagation(); onToggle(sortKey); }}
        className="flex items-center gap-1 text-inherit hover:text-foreground transition-colors cursor-pointer"
      >
        {label}
        {active && (asc
          ? <ArrowUp className="w-3 h-3" />
          : <ArrowDown className="w-3 h-3" />
        )}
      </button>
    </TableHead>
  );
}


// ---------------------------------------------------------------------------
// Env editor floating window
// ---------------------------------------------------------------------------

function EnvEditorWindow({
  win,
  focused,
  onUpdate,
  onClose,
  onFocus,
}: {
  win: ManagedWindow<EnvWinData>;
  focused: boolean;
  onUpdate: (id: string, patch: Partial<ManagedWindow<EnvWinData>>) => void;
  onClose: (id: string) => void;
  onFocus: (id: string) => void;
}) {
  const windowRef = useRef<HTMLDivElement>(null);
  const [content, setContent] = useState("");
  const [isDirty, setIsDirty] = useState(false);
  const [saving, setSaving] = useState(false);

  useEffect(() => {
    api.fetchEnv().then((c) => setContent(c));
  }, []);

  const handleChange = useCallback((v: string) => {
    setContent(v);
    setIsDirty(true);
  }, []);

  const handleSave = useCallback(async () => {
    setSaving(true);
    try {
      await api.saveEnv(content);
      setIsDirty(false);
      toast.success(".env saved");
    } catch (e) {
      toast.error(`Save failed: ${e}`);
    } finally {
      setSaving(false);
    }
  }, [content]);

  useEffect(() => {
    if (!focused) return;
    const handler = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key === "s") {
        e.preventDefault();
        handleSave();
      }
    };
    window.addEventListener("keydown", handler);
    return () => window.removeEventListener("keydown", handler);
  }, [focused, handleSave]);

  const handleClose = useCallback((id: string) => {
    if (isDirty && !window.confirm("You have unsaved changes. Close anyway?")) return;
    onClose(id);
  }, [isDirty, onClose]);

  return (
    <FloatingWindow
      id={win.id}
      title=".env"
      x={win.x} y={win.y} w={win.w} h={win.h}
      zIndex={win.zIndex}
      focused={focused}
      onUpdate={onUpdate}
      onClose={handleClose}
      onFocus={onFocus}
      minW={360} minH={200}
      containerRef={windowRef}
    >
      <EditorPointer containerRef={windowRef} focused={focused} />
      <div className="flex flex-col h-full">
        {/* Toolbar */}
        <div className="flex items-center px-3 py-1.5 border-b-2 border-border shrink-0 gap-2">
          <KeyRound className="w-3.5 h-3.5 text-amber-500/70" />
          <span className="text-xs font-semibold flex-1">Environment Variables</span>
          <button
            onClick={handleSave}
            disabled={saving || !isDirty}
            className="text-[10px] uppercase tracking-wider text-muted-foreground hover:text-foreground disabled:opacity-40 transition-colors cursor-pointer"
          >
            {saving ? "Saving..." : "Save"}
          </button>
        </div>
        {/* Help */}
        <div className="px-3 py-1.5 border-b border-border bg-muted/10 text-[10px] text-muted-foreground">
          One variable per line: <span className="font-mono">KEY=value</span>. Use <span className="font-mono">source name : env "KEY"</span> in pages.
        </div>
        {/* CodeMirror editor */}
        <div className="flex-1 min-h-0">
          <EditorPane value={content} onChange={handleChange} />
        </div>
      </div>
    </FloatingWindow>
  );
}
