import { useAtomValue, useSetAtom } from "jotai";
import { Check } from "lucide-react";
import { type KeyboardEvent, type ReactElement, useEffect, useRef } from "react";
import { EmptyState, Popover, Tag, ThemedIcon } from "../../../../components/ui";
import { useViewport } from "../../../../hooks/use-viewport";
import { useTranslation } from "../../../../lib/i18n";
import { MobileSelectSheet } from "../../../mobile-select";
import { useBranchQuickPickActions } from "../../actions/use-git-actions";
import { branchQuickPickAtom } from "../../atoms";

const branchQuickPickEmptyStateStyle = {
  minHeight: "auto",
  padding: "var(--sp-8)",
  gap: 0,
};

const branchQuickPickEmptyStateTitleStyle = {
  margin: 0,
  color: "var(--text-tertiary)",
  fontWeight: "var(--font-normal)",
};

function BranchQuickPickEmptyState({ title }: { title: string }) {
  return (
    <EmptyState
      className="branch-quick-pick-empty"
      style={branchQuickPickEmptyStateStyle}
      title={<p style={branchQuickPickEmptyStateTitleStyle}>{title}</p>}
    />
  );
}

function BranchQuickPickContent() {
  const t = useTranslation();
  const {
    branchList,
    displayItems,
    handleBranchCreate,
    handleBranchSelect,
    handleClose,
    handleRequestBranchCreate,
    inputValue,
    isBranchSelectable,
    selectedIndex,
    setInputValue,
    setPendingCreateBranchName,
    setSelectedIndex,
    trimmedInput,
  } = useBranchQuickPickActions();
  const inputRef = useRef<HTMLInputElement>(null);
  const listRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const focusTimeout = window.setTimeout(() => {
      inputRef.current?.focus();
    }, 0);

    return () => {
      window.clearTimeout(focusTimeout);
    };
  }, []);

  useEffect(() => {
    if (!listRef.current) {
      return;
    }

    const selectedElement = listRef.current.querySelector(
      `.branch-quick-pick-item:nth-child(${selectedIndex + 1})`
    );
    selectedElement?.scrollIntoView({ block: "nearest" });
  }, [selectedIndex]);

  const handleKeyDown = (event: KeyboardEvent) => {
    switch (event.key) {
      case "ArrowDown":
        event.preventDefault();
        setSelectedIndex((prev) => (prev < displayItems.length - 1 ? prev + 1 : prev));
        break;
      case "ArrowUp":
        event.preventDefault();
        setSelectedIndex((prev) => (prev > 0 ? prev - 1 : prev));
        break;
      case "Enter":
        event.preventDefault();
        if (displayItems[selectedIndex]) {
          const item = displayItems[selectedIndex];
          if (item.type === "branch" && item.branch) {
            if (!isBranchSelectable(item.branch)) {
              return;
            }
            void handleBranchSelect(item.branch.name);
          } else if (item.type === "create") {
            handleRequestBranchCreate(trimmedInput);
          } else if (item.type === "confirm-create") {
            void handleBranchCreate(trimmedInput);
          }
        }
        break;
      case "Escape":
        event.preventDefault();
        handleClose();
        break;
    }
  };

  return (
    <>
      <div className="branch-quick-pick-search">
        <input
          ref={inputRef}
          type="text"
          className="branch-quick-pick-input"
          placeholder={t("git.quick_pick.search_placeholder")}
          value={inputValue}
          onChange={(event) => {
            setInputValue(event.target.value);
            setPendingCreateBranchName(null);
            setSelectedIndex(0);
          }}
          onKeyDown={handleKeyDown}
        />
      </div>

      <div className="branch-quick-pick-list" ref={listRef}>
        {branchList.loading ? (
          <BranchQuickPickEmptyState title={t("git.quick_pick.loading")} />
        ) : displayItems.length > 0 ? (
          displayItems.map((item, index) => (
            <div
              key={item.type === "branch" ? item.branch?.name : "create"}
              className={`branch-quick-pick-item ${
                index === selectedIndex ? "branch-quick-pick-item-selected" : ""
              }`}
              onClick={() => {
                if (item.type === "branch" && item.branch) {
                  if (!isBranchSelectable(item.branch)) {
                    return;
                  }
                  void handleBranchSelect(item.branch.name);
                } else if (item.type === "create") {
                  handleRequestBranchCreate(trimmedInput);
                } else if (item.type === "confirm-create") {
                  void handleBranchCreate(trimmedInput);
                }
              }}
              onMouseEnter={() => setSelectedIndex(index)}
            >
              {item.type === "branch" && item.branch ? (
                <>
                  {item.branch.isCurrent && (
                    <span className="branch-quick-pick-check">
                      <Check size={14} />
                    </span>
                  )}

                  <span className="branch-quick-pick-name">{item.branch.name}</span>

                  {item.branch.linkedWorktreePath && !item.branch.isCurrent && (
                    <Tag color="neutral" caps={false} className="branch-quick-pick-badge">
                      {t("git.quick_pick.in_use")}
                    </Tag>
                  )}

                  {item.branch.isRemote && (
                    <Tag color="neutral" caps={false} className="branch-quick-pick-badge">
                      {t("git.branch_remote")}
                    </Tag>
                  )}
                </>
              ) : (
                <>
                  <span className="branch-quick-pick-create-icon">
                    <ThemedIcon semantic="git.branch.create" size={14} />
                  </span>
                  <span className="branch-quick-pick-create-label">{item.label}</span>
                </>
              )}
            </div>
          ))
        ) : (
          <BranchQuickPickEmptyState
            title={inputValue ? t("git.quick_pick.empty_filtered") : t("git.quick_pick.empty_idle")}
          />
        )}
      </div>

      <div className="branch-quick-pick-hint">
        <span>↑↓ {t("git.quick_pick.hint_navigate")}</span>
        <span>↵ {t("git.quick_pick.hint_select")}</span>
        <span>Esc {t("git.quick_pick.hint_close")}</span>
      </div>
    </>
  );
}

interface DesktopBranchQuickPickPopoverProps {
  children: ReactElement;
  workspaceId: string;
  onOpenBranchSwitcher?: () => void;
}

export function DesktopBranchQuickPickPopover({
  children,
  workspaceId,
  onOpenBranchSwitcher,
}: DesktopBranchQuickPickPopoverProps) {
  const viewport = useViewport();
  const t = useTranslation();
  const quickPickState = useAtomValue(branchQuickPickAtom);
  const setQuickPick = useSetAtom(branchQuickPickAtom);

  if (viewport === "mobile" || !onOpenBranchSwitcher) {
    return children;
  }

  return (
    <Popover
      content={<BranchQuickPickContent />}
      contentClassName="branch-quick-pick"
      forceMode="desktop"
      onOpenChange={(open) => {
        if (open) {
          onOpenBranchSwitcher();
          return;
        }

        setQuickPick({
          visible: false,
          inputValue: "",
        });
      }}
      open={quickPickState.visible && quickPickState.workspaceId === workspaceId}
      title={t("git.branch")}
    >
      {children}
    </Popover>
  );
}

export function BranchQuickPick() {
  const viewport = useViewport();
  const t = useTranslation();
  const {
    branchList,
    displayItems,
    handleBranchCreate,
    handleBranchSelect,
    handleClose,
    handleRequestBranchCreate,
    inputValue,
    isBranchSelectable,
    quickPickState,
    selectedIndex,
    setInputValue,
    setPendingCreateBranchName,
    setSelectedIndex,
    trimmedInput,
  } = useBranchQuickPickActions();

  const handleKeyDown = (event: KeyboardEvent) => {
    switch (event.key) {
      case "ArrowDown":
        event.preventDefault();
        setSelectedIndex((prev) => (prev < displayItems.length - 1 ? prev + 1 : prev));
        break;
      case "ArrowUp":
        event.preventDefault();
        setSelectedIndex((prev) => (prev > 0 ? prev - 1 : prev));
        break;
      case "Enter":
        event.preventDefault();
        if (displayItems[selectedIndex]) {
          const item = displayItems[selectedIndex];
          if (item.type === "branch" && item.branch) {
            if (!isBranchSelectable(item.branch)) {
              return;
            }
            void handleBranchSelect(item.branch.name);
          } else if (item.type === "create") {
            handleRequestBranchCreate(trimmedInput);
          } else if (item.type === "confirm-create") {
            void handleBranchCreate(trimmedInput);
          }
        }
        break;
      case "Escape":
        event.preventDefault();
        handleClose();
        break;
    }
  };

  if (!quickPickState.visible || viewport !== "mobile") {
    return null;
  }

  const selectedItem = displayItems[selectedIndex] ?? null;
  const selectedId =
    selectedItem?.type === "branch" && selectedItem.branch ? selectedItem.branch.name : null;
  const hasExactMatch = displayItems.some(
    (item) =>
      item.type === "branch" && item.branch?.name.toLowerCase() === trimmedInput.toLowerCase()
  );
  const branchItems = displayItems
    .filter((item) => item.type === "branch" && item.branch)
    .map((item) => ({
      id: item.branch!.name,
      label: item.branch!.name,
      icon: item.branch!.isCurrent ? <Check size={14} /> : undefined,
      meta: item.branch!.isCurrent
        ? t("git.current_branch")
        : item.branch!.linkedWorktreePath
          ? t("git.quick_pick.worktree_in_use")
          : undefined,
      badge: item.branch!.isRemote ? t("git.branch_remote") : undefined,
      disabled: !isBranchSelectable(item.branch!),
    }));
  const createItem = displayItems.find(
    (item) => item.type === "create" || item.type === "confirm-create"
  );

  return (
    <div onKeyDown={handleKeyDown}>
      <MobileSelectSheet
        className="mobile-select-sheet--command"
        title={t("git.branch")}
        searchable
        searchPlaceholder={t("git.quick_pick.search_placeholder")}
        searchValue={inputValue}
        onSearchValueChange={(value) => {
          setInputValue(value);
          setPendingCreateBranchName(null);
          setSelectedIndex(0);
        }}
        sections={[
          {
            kind: "options",
            id: "branches",
            items: branchItems,
          },
        ]}
        closeOnSelect={false}
        selectedId={selectedId}
        loading={branchList.loading}
        loadingText={t("git.quick_pick.loading")}
        emptyText={inputValue ? t("git.quick_pick.empty_filtered") : t("git.quick_pick.empty_idle")}
        create={{
          visible: Boolean(trimmedInput) && !hasExactMatch,
          label: () =>
            createItem?.type === "confirm-create"
              ? t("git.quick_pick.confirm_create_label")
              : t("git.quick_pick.create_label"),
          description: () => trimmedInput,
          onCreate: async () => {
            if (createItem?.type === "confirm-create") {
              await handleBranchCreate(trimmedInput);
              return;
            }

            handleRequestBranchCreate(trimmedInput);
            setSelectedIndex(displayItems.length - 1);
          },
        }}
        onClose={handleClose}
        onSelect={handleBranchSelect}
      />
    </div>
  );
}
