import { useEffect, useRef, useState } from "react";
import { invoke } from "@tauri-apps/api/core";
import { getCurrentWindow } from "@tauri-apps/api/window";

type DesktopStatus = "loading" | "ready" | "error";
type CheckStatus = "pass" | "warn" | "fail";

type DesktopCheck = {
  id: string;
  label: string;
  status: CheckStatus;
  detail: string;
};

type DesktopDependency = {
  name: string;
  description: string;
  website?: string;
  status: CheckStatus;
  path?: string;
  version?: string;
  verify_command: string;
  install_commands: string[];
  detail: string;
};

type GitCommitBinding = {
  github_login: string;
  commit_name: string;
  commit_email: string;
};

type DesktopProfile = {
  identity: string;
  handle: string;
  display_name: string;
  rho_home: string;
  source: string;
  has_local_private_keys: boolean;
  signing_key_path?: string;
  encryption_key_path?: string;
  proof_verified: boolean;
  proof_url?: string;
  git_commit_binding?: GitCommitBinding;
};

type ProfileSelection = {
  identity?: string;
  rho_home?: string;
};

type CommandResult = {
  ok: boolean;
  code?: number;
  stdout: string;
  stderr: string;
};

type GitHubAccount = {
  login: string;
  host: string;
  active: boolean;
  state: string;
  git_protocol: string;
  token_source: string;
  matching_identity: string;
  has_rho_profile: boolean;
  has_local_private_keys: boolean;
  signing_key_path?: string;
  encryption_key_path?: string;
  proof_verified: boolean;
  proof_url?: string;
  git_commit_binding?: GitCommitBinding;
};

type OnboardingState = {
  rho_home: string;
  gh_accounts: GitHubAccount[];
  local_profiles: DesktopProfile[];
};

type DesktopProject = {
  id: string;
  name: string;
  path: string;
  exists: boolean;
  is_git: boolean;
  is_rho: boolean;
  rho_project_id?: string;
  owner?: string;
  role: string;
  current_branch?: string;
  remote_url?: string;
  dirty: boolean;
  upstream?: string;
  ahead: number;
  behind: number;
  status_summary: string;
  warning?: string;
};

type FileEntry = {
  path: string;
  kind: string;
  status?: string;
};

type MemberInfo = {
  identity: string;
  handle: string;
  role: string;
};

type ParticipantInfo = {
  handle: string;
  identity?: string;
  display_name?: string;
  signing_fingerprint?: string;
  encryption_fingerprint?: string;
  proof_url?: string;
};

type RepoFileSummary = {
  path: string;
  title: string;
  summary: string;
};

type ToolInfo = {
  id: string;
  action_type?: string;
  owner?: string;
  approval_required: boolean;
  path: string;
};

type MessageInfo = {
  path: string;
  inbox: string;
  thread: string;
  kind: string;
  encrypted: boolean;
  signed: boolean;
  summary: string;
};

type PendingAction = {
  id: string;
  kind: string;
  actor?: string;
  summary: string;
  path: string;
};

type GitStatusEntry = {
  path: string;
  status: string;
};

type RepoDetail = {
  project: DesktopProject;
  files: FileEntry[];
  members: MemberInfo[];
  participants: ParticipantInfo[];
  policy_files: RepoFileSummary[];
  tools: ToolInfo[];
  messages: MessageInfo[];
  pending_actions: PendingAction[];
  status_entries: GitStatusEntry[];
};

type NavIconName =
  | "setup"
  | "projects"
  | "messages"
  | "activity"
  | "settings"
  | "refresh"
  | "bug"
  | "sun"
  | "moon";

function NavIcon({ name }: { name: NavIconName }) {
  const common = {
    width: 18,
    height: 18,
    viewBox: "0 0 24 24",
    fill: "none",
    stroke: "currentColor",
    strokeWidth: 2,
    strokeLinecap: "round" as const,
    strokeLinejoin: "round" as const,
    "aria-hidden": true
  };

  if (name === "setup") {
    return (
      <svg {...common}>
        <path d="M21 12a9 9 0 1 1-2.64-6.36" />
        <path d="m9 12 2 2 4-5" />
      </svg>
    );
  }
  if (name === "projects") {
    return (
      <svg {...common}>
        <path d="M3 7a2 2 0 0 1 2-2h5l2 2h7a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z" />
      </svg>
    );
  }
  if (name === "messages") {
    return (
      <svg {...common}>
        <path d="M21 15a4 4 0 0 1-4 4H8l-5 3V7a4 4 0 0 1 4-4h10a4 4 0 0 1 4 4Z" />
      </svg>
    );
  }
  if (name === "activity") {
    return (
      <svg {...common}>
        <path d="M3 12h4l3 8 4-16 3 8h4" />
      </svg>
    );
  }
  if (name === "sun") {
    return (
      <svg {...common}>
        <circle cx="12" cy="12" r="4" />
        <path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4" />
      </svg>
    );
  }
  if (name === "moon") {
    return (
      <svg {...common}>
        <path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8Z" />
      </svg>
    );
  }
  if (name === "bug") {
    return (
      <svg {...common}>
        <path d="M8 6a4 4 0 0 1 8 0" />
        <rect x="8" y="6" width="8" height="12" rx="4" />
        <path d="M3 11h3M18 11h3M3 17h4M17 17h4M12 6v14" />
      </svg>
    );
  }
  if (name === "settings") {
    return (
      <svg {...common}>
        <path d="M12 15.5A3.5 3.5 0 1 0 12 8a3.5 3.5 0 0 0 0 7.5Z" />
        <path d="M19.4 15a1.8 1.8 0 0 0 .36 1.98l.04.04a2 2 0 1 1-2.83 2.83l-.04-.04A1.8 1.8 0 0 0 15 19.4a1.8 1.8 0 0 0-1 .6 1.8 1.8 0 0 0-.4 1.1V21a2 2 0 1 1-4 0v-.08A1.8 1.8 0 0 0 8.6 19.4a1.8 1.8 0 0 0-1.98.36l-.04.04a2 2 0 1 1-2.83-2.83l.04-.04A1.8 1.8 0 0 0 4.6 15a1.8 1.8 0 0 0-.6-1 1.8 1.8 0 0 0-1.1-.4H3a2 2 0 1 1 0-4h.08A1.8 1.8 0 0 0 4.6 8.6a1.8 1.8 0 0 0-.36-1.98l-.04-.04a2 2 0 1 1 2.83-2.83l.04.04A1.8 1.8 0 0 0 9 4.6a1.8 1.8 0 0 0 1-.6 1.8 1.8 0 0 0 .4-1.1V3a2 2 0 1 1 4 0v.08A1.8 1.8 0 0 0 15.4 4.6a1.8 1.8 0 0 0 1.98-.36l.04-.04a2 2 0 1 1 2.83 2.83l-.04.04A1.8 1.8 0 0 0 19.4 9a1.8 1.8 0 0 0 .6 1 1.8 1.8 0 0 0 1.1.4H21a2 2 0 1 1 0 4h-.08A1.8 1.8 0 0 0 19.4 15Z" />
      </svg>
    );
  }
  return (
    <svg {...common}>
      <path d="M21 12a9 9 0 0 1-9 9 8.7 8.7 0 0 1-6.4-2.8" />
      <path d="M3 12a9 9 0 0 1 15.1-6.6" />
      <path d="M18 2v4h-4" />
      <path d="M6 22v-4h4" />
    </svg>
  );
}

function ClipboardIcon({ copied }: { copied: boolean }) {
  if (copied) {
    return (
      <svg
        width={15}
        height={15}
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        strokeWidth={2.4}
        strokeLinecap="round"
        strokeLinejoin="round"
        aria-hidden={true}
      >
        <path d="m5 13 4 4L19 7" />
      </svg>
    );
  }
  return (
    <svg
      width={15}
      height={15}
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth={2}
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden={true}
    >
      <rect x="9" y="9" width="11" height="11" rx="2" />
      <path d="M5 15V5a2 2 0 0 1 2-2h10" />
    </svg>
  );
}

function RhoLogo({ size = 26 }: { size?: number }) {
  return (
    <svg
      viewBox="0 0 1024 1024"
      width={size}
      height={size}
      fill="none"
      stroke="currentColor"
      strokeWidth={80}
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden={true}
    >
      <path d="M 510 930 V 245 A 195 195 0 1 1 510 575" />
      <path d="M 388 575 H 510" />
      <path d="M 437 852 H 583" />
    </svg>
  );
}

function FolderIcon() {
  return (
    <svg
      width={16}
      height={16}
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth={2}
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden={true}
    >
      <path d="M3 7a2 2 0 0 1 2-2h5l2 2h7a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z" />
    </svg>
  );
}

// Logins whose avatar failed to load — kept so we don't retry a broken image or
// flicker back to it on re-mount. Successful images are served from the webview's
// HTTP cache by URL, so an <img> (CORS-free, unlike fetch) won't reload.
const avatarFailed = new Set<string>();

function Avatar({ login, size = 40 }: { login: string; size?: number }) {
  const [failed, setFailed] = useState(() => avatarFailed.has(login));
  if (failed || !login) {
    return (
      <span
        className="avatar avatar-fallback"
        style={{ width: size, height: size, fontSize: Math.round(size * 0.4) }}
      >
        {(login.slice(0, 1) || "?").toUpperCase()}
      </span>
    );
  }
  return (
    <img
      className="avatar"
      src={`https://github.com/${encodeURIComponent(login)}.png?size=${Math.round(size * 2)}`}
      width={size}
      height={size}
      alt=""
      onError={() => {
        avatarFailed.add(login);
        setFailed(true);
      }}
    />
  );
}

function AppRail({
  active,
  onReportBug,
  onOpenSettings,
  onOpenProfiles,
  onOpenProjects,
  onToggleTheme,
  theme,
  currentLogin
}: {
  active: "setup" | "projects" | "messages" | "settings";
  onReportBug: () => void;
  onOpenSettings: () => void;
  onOpenProfiles: () => void;
  onOpenProjects: () => void;
  onToggleTheme: () => void;
  theme: "light" | "dark";
  currentLogin?: string;
}) {
  return (
    <aside className="desktop-sidebar" aria-label="Rho navigation">
      <div className="sidebar-brand" title="Rho">
        <RhoLogo size={24} />
      </div>
      <button
        type="button"
        className="sidebar-icon"
        data-active={active === "projects"}
        onClick={onOpenProjects}
        title="Projects"
      >
        <NavIcon name="projects" />
      </button>
      <button
        type="button"
        className="sidebar-icon"
        data-active={active === "messages"}
        disabled
        title="Messages"
      >
        <NavIcon name="messages" />
      </button>
      <button
        type="button"
        className="sidebar-icon sidebar-bottom"
        onClick={onToggleTheme}
        title={theme === "dark" ? "Dark mode (switch to light)" : "Light mode (switch to dark)"}
      >
        <NavIcon name={theme === "dark" ? "moon" : "sun"} />
      </button>
      <button type="button" className="sidebar-icon" onClick={onReportBug} title="Report a bug">
        <NavIcon name="bug" />
      </button>
      {currentLogin ? (
        <button
          type="button"
          className="sidebar-icon sidebar-profile"
          onClick={onOpenProfiles}
          title={`Profile: ${currentLogin} — switch`}
        >
          <Avatar login={currentLogin} size={30} />
        </button>
      ) : null}
      <button
        type="button"
        className="sidebar-icon"
        data-active={active === "settings"}
        onClick={onOpenSettings}
        title="Settings"
      >
        <NavIcon name="settings" />
      </button>
    </aside>
  );
}

export default function App() {
  const [status, setStatus] = useState<DesktopStatus>("loading");
  const [version, setVersion] = useState<string>("");
  const [error, setError] = useState<string>("");
  const [profiles, setProfiles] = useState<DesktopProfile[]>([]);
  const [dependencies, setDependencies] = useState<DesktopDependency[]>([]);
  const [selectedDependencyName, setSelectedDependencyName] = useState<string>("");
  const [dependenciesError, setDependenciesError] = useState<string>("");
  const [isCheckingDependencies, setIsCheckingDependencies] = useState<boolean>(false);
  const [selectedIdentity, setSelectedIdentity] = useState<string>("");
  const [checks, setChecks] = useState<DesktopCheck[]>([]);
  const [isChecking, setIsChecking] = useState<boolean>(false);
  const [actionResult, setActionResult] = useState<string>("");
  const [isSwitchingGh, setIsSwitchingGh] = useState<boolean>(false);
  const [isCheckingEnv, setIsCheckingEnv] = useState<boolean>(false);
  const [projects, setProjects] = useState<DesktopProject[]>([]);
  const [projectsError, setProjectsError] = useState<string>("");
  const [isLoadingProjects, setIsLoadingProjects] = useState<boolean>(false);
  const [isAddingProject, setIsAddingProject] = useState<boolean>(false);
  const [isCloningProject, setIsCloningProject] = useState<boolean>(false);
  const [isSettingUpRhoRepo, setIsSettingUpRhoRepo] = useState<boolean>(false);
  const [localProjectPath, setLocalProjectPath] = useState<string>("");
  const [cloneUrl, setCloneUrl] = useState<string>("");
  const [cloneDestination, setCloneDestination] = useState<string>("");
  const [setupRepoPath, setSetupRepoPath] = useState<string>("");
  const [setupRepoId, setSetupRepoId] = useState<string>("");
  const [setupRemoteUrl, setSetupRemoteUrl] = useState<string>("");
  const [setupProtectOwnerInbox, setSetupProtectOwnerInbox] = useState<boolean>(true);
  const [selectedProjectPath, setSelectedProjectPath] = useState<string>("");
  const [repoDetail, setRepoDetail] = useState<RepoDetail | null>(null);
  const [repoDetailError, setRepoDetailError] = useState<string>("");
  const [isLoadingRepoDetail, setIsLoadingRepoDetail] = useState<boolean>(false);
  const [onboarding, setOnboarding] = useState<OnboardingState | null>(null);
  const [onboardingError, setOnboardingError] = useState<string>("");
  const [isLoadingOnboarding, setIsLoadingOnboarding] = useState<boolean>(false);
  const [isCreatingProfile, setIsCreatingProfile] = useState<string>("");
  const [isVerifyingProfile, setIsVerifyingProfile] = useState<string>("");
  const [isBindingCommitAuthor, setIsBindingCommitAuthor] = useState<string>("");
  const [manualHandle, setManualHandle] = useState<string>("");
  const [repoActionTargetHandle, setRepoActionTargetHandle] = useState<string>("");
  const [repoActionRequestId, setRepoActionRequestId] = useState<string>("");
  const [isRunningRepoAction, setIsRunningRepoAction] = useState<string>("");
  const [commitMessage, setCommitMessage] = useState<string>("");
  const [isCommittingRepo, setIsCommittingRepo] = useState<boolean>(false);
  const [messageRecipient, setMessageRecipient] = useState<string>("");
  const [messageThread, setMessageThread] = useState<string>("");
  const [messageText, setMessageText] = useState<string>("");
  const [isSendingMessage, setIsSendingMessage] = useState<boolean>(false);
  const [branchName, setBranchName] = useState<string>("");
  const [isRunningGitAction, setIsRunningGitAction] = useState<string>("");
  const [onboardingStep, setOnboardingStep] = useState<"tools" | "accounts" | "profile">("tools");
  const [toolsSkipped, setToolsSkipped] = useState<boolean>(false);
  const [isOpeningTerminal, setIsOpeningTerminal] = useState<boolean>(false);
  const [copiedField, setCopiedField] = useState<string>("");
  const [showProfileSwitcher, setShowProfileSwitcher] = useState<boolean>(false);
  const [view, setView] = useState<"onboarding" | "projects" | "settings">("onboarding");
  const [hiddenProfiles, setHiddenProfiles] = useState<string[]>(() => {
    try {
      const raw = window.localStorage.getItem("rho.desktop.hiddenProfiles");
      return raw ? (JSON.parse(raw) as string[]) : [];
    } catch {
      return [];
    }
  });
  const [theme, setTheme] = useState<"light" | "dark">(() => {
    const saved = window.localStorage.getItem("rho.desktop.theme");
    if (saved === "light" || saved === "dark") {
      return saved;
    }
    return window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
  });
  const [proofIssue, setProofIssue] = useState<{
    handle: string;
    kind: "missing" | "invalid";
  } | null>(null);

  useEffect(() => {
    const queryIdentity = new URLSearchParams(window.location.search).get("identity") ?? "";

    void Promise.all([
      invoke<string>("app_version"),
      invoke<DesktopProfile[]>("desktop_profiles"),
      invoke<OnboardingState>("desktop_onboarding"),
      invoke<DesktopDependency[]>("desktop_dependencies"),
      invoke<string | null>("launch_identity").catch(() => null)
    ])
      .then(([value, discoveredProfiles, onboardingState, dependencyState, launchedIdentity]) => {
        setVersion(value);
        setProfiles(discoveredProfiles);
        setOnboarding(onboardingState);
        setDependencies(dependencyState);
        setSelectedDependencyName(dependencyState[0]?.name || "");
        setSelectedIdentity(
          queryIdentity || launchedIdentity || discoveredProfiles[0]?.identity || ""
        );
        // Land on Projects if a profile already exists; otherwise start onboarding.
        setView(discoveredProfiles.length > 0 ? "projects" : "onboarding");
        setStatus("ready");
      })
      .catch((cause: unknown) => {
        setError(cause instanceof Error ? cause.message : String(cause));
        setStatus("error");
      });
  }, []);

  useEffect(() => {
    if (status !== "ready") {
      return;
    }
    void runChecks(selectedIdentity);
    void loadProjects(selectedIdentity);
    setSelectedProjectPath("");
    setRepoDetail(null);
  }, [selectedIdentity, status]);

  const selectedProfile = profiles.find((profile) => profile.identity === selectedIdentity);
  const selectedHandle = selectedProfile?.handle || githubHandle(selectedIdentity);
  const selectedAccount = onboarding?.gh_accounts.find((account) => account.login === selectedHandle);
  const prerequisiteIds = ["rho_cli", "git", "gh", "gh_auth"];
  const prerequisiteChecks = checks.filter((check) => prerequisiteIds.includes(check.id));
  const profileChecks = checks.filter((check) => !prerequisiteIds.includes(check.id));
  const prerequisitesReady =
    prerequisiteChecks.length >= prerequisiteIds.length &&
    prerequisiteChecks.every((check) => check.status === "pass");
  const selectedProfileReady = selectedAccount
    ? isAccountReady(selectedAccount)
    : Boolean(
        selectedProfile?.has_local_private_keys &&
          selectedProfile.proof_verified &&
          selectedProfile.git_commit_binding
      );
  const finalReadinessReady =
    prerequisitesReady && selectedProfileReady && checks.every((check) => check.status === "pass");
  const visibleDependencies = dependencies.filter((dependency) => dependency.name !== "rho");
  const allDependenciesReady =
    visibleDependencies.length > 0 &&
    visibleDependencies.every((dependency) => dependency.status === "pass");
  const selectedDependency =
    visibleDependencies.find((dependency) => dependency.name === selectedDependencyName) ||
    visibleDependencies[0];
  const shouldShowOnboarding = view === "onboarding";
  const hasUsableProfiles = profiles.length > 0;
  const didAutoSkipTools = useRef(false);
  const prevOnboardingStep = useRef(onboardingStep);

  // Latest values for the once-registered focus listener, so it never has to
  // re-register (re-registering churns Tauri's event map and races its cleanup).
  const focusCtx = useRef({
    onboardingStep,
    selectedAccount,
    isVerifyingProfile,
    verify: verifyProfileForHandle
  });
  focusCtx.current = {
    onboardingStep,
    selectedAccount,
    isVerifyingProfile,
    verify: verifyProfileForHandle
  };

  // Re-check the GitHub proof against the live profile every time the user opens
  // the Prepare step, so the "verified" badge reflects reality.
  useEffect(() => {
    const enteringProfile =
      onboardingStep === "profile" && prevOnboardingStep.current !== "profile";
    prevOnboardingStep.current = onboardingStep;
    if (enteringProfile && selectedAccount?.has_rho_profile && !isVerifyingProfile) {
      void verifyProfileForHandle(selectedAccount.login);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [onboardingStep, selectedAccount?.login, selectedAccount?.has_rho_profile]);

  // Re-check on app-window focus (e.g. after editing GitHub in the browser and
  // switching back). Registered ONCE; reads current state via focusCtx ref.
  useEffect(() => {
    let unlisten: (() => void) | undefined;
    let cancelled = false;
    void getCurrentWindow()
      .onFocusChanged(({ payload: focused }) => {
        if (!focused) {
          return;
        }
        const ctx = focusCtx.current;
        if (
          ctx.onboardingStep === "profile" &&
          ctx.selectedAccount?.has_rho_profile &&
          !ctx.isVerifyingProfile
        ) {
          void ctx.verify(ctx.selectedAccount.login);
        }
      })
      .then((fn) => {
        if (cancelled) {
          fn();
        } else {
          unlisten = fn;
        }
      });
    return () => {
      cancelled = true;
      unlisten?.();
    };
  }, []);

  useEffect(() => {
    document.documentElement.setAttribute("data-theme", theme);
    window.localStorage.setItem("rho.desktop.theme", theme);
  }, [theme]);

  useEffect(() => {
    if (
      status === "ready" &&
      allDependenciesReady &&
      !didAutoSkipTools.current &&
      onboardingStep === "tools"
    ) {
      didAutoSkipTools.current = true;
      setOnboardingStep("accounts");
    }
  }, [status, allDependenciesReady, onboardingStep]);

  function selection(identity = selectedIdentity): ProfileSelection | undefined {
    const profile = profiles.find((candidate) => candidate.identity === identity);
    if (!profile && !identity) {
      return undefined;
    }
    return {
      identity: identity || profile?.identity,
      rho_home: profile?.rho_home
    };
  }

  function githubHandle(identity?: string): string {
    return (
      identity
        ?.replace("rho://id/github/", "")
        .replace("github/", "")
        .trim() || ""
    );
  }

  function isAccountReady(account?: GitHubAccount): boolean {
    return Boolean(
      account?.has_rho_profile &&
        account.has_local_private_keys &&
        account.proof_verified &&
        account.git_commit_binding
    );
  }

  function dependencyTitle(name: string): string {
    const titles: Record<string, string> = { gh: "GitHub CLI", git: "Git" };
    return titles[name] || name;
  }

  function statusLabel(statusValue: CheckStatus): string {
    if (statusValue === "pass") {
      return "Ready";
    }
    if (statusValue === "warn") {
      return "Needs attention";
    }
    return "Blocked";
  }

  function accountChecklist(account: GitHubAccount) {
    return [
      {
        label: "Rho profile",
        ok: account.has_rho_profile,
        detail: account.has_rho_profile ? account.matching_identity : "Not created"
      },
      {
        label: "Private keys",
        ok: account.has_local_private_keys,
        detail: account.has_local_private_keys ? "Signing and encryption keys found" : "Keys missing"
      },
      {
        label: "GitHub proof",
        ok: account.proof_verified,
        detail: account.proof_verified ? "Verified" : account.proof_url || "Not verified"
      },
      {
        label: "Commit author",
        ok: Boolean(account.git_commit_binding),
        detail: account.git_commit_binding
          ? `${account.git_commit_binding.commit_name} <${account.git_commit_binding.commit_email}>`
          : "Not bound"
      }
    ];
  }

  function dismissOnboarding() {
    setView("projects");
  }

  function finishOnboarding() {
    const ready = Boolean(selectedAccount?.has_rho_profile && selectedAccount?.proof_verified);
    if (!ready) {
      const proceed = window.confirm(
        "Your profile setup isn't complete yet (GitHub proof not verified). Continue anyway?"
      );
      if (!proceed) {
        return;
      }
    }
    dismissOnboarding();
  }

  function resetOnboarding() {
    setView("onboarding");
  }

  function chooseAccount(account: GitHubAccount) {
    const profile = profileForHandle(account.login);
    setSelectedIdentity(profile?.identity || account.matching_identity);
    setProofIssue(null);
  }

  async function runChecks(identity = selectedIdentity) {
    setIsChecking(true);
    try {
      const result = await invoke<DesktopCheck[]>("desktop_checks", {
        profile: selection(identity)
      });
      setChecks(result);
    } catch (cause) {
      setError(cause instanceof Error ? cause.message : String(cause));
      setStatus("error");
    } finally {
      setIsChecking(false);
    }
  }

  async function refreshProfilesAndOnboarding(preferredHandle?: string) {
    setIsLoadingOnboarding(true);
    setOnboardingError("");
    try {
      const [discoveredProfiles, onboardingState] = await Promise.all([
        invoke<DesktopProfile[]>("desktop_profiles"),
        invoke<OnboardingState>("desktop_onboarding")
      ]);
      setProfiles(discoveredProfiles);
      setOnboarding(onboardingState);
      if (preferredHandle) {
        const profile = discoveredProfiles.find((candidate) => candidate.handle === preferredHandle);
        if (profile) {
          setSelectedIdentity(profile.identity);
        }
      } else if (!selectedIdentity && discoveredProfiles[0]) {
        setSelectedIdentity(discoveredProfiles[0].identity);
      }
    } catch (cause) {
      setOnboardingError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsLoadingOnboarding(false);
    }
  }

  async function refreshDependencies() {
    setIsCheckingDependencies(true);
    setDependenciesError("");
    try {
      const dependencyState = await invoke<DesktopDependency[]>("desktop_dependencies");
      setDependencies(dependencyState);
      setSelectedDependencyName((current) => current || dependencyState[0]?.name || "");
    } catch (cause) {
      setDependenciesError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsCheckingDependencies(false);
    }
  }

  async function openProfileWindow() {
    await invoke("open_profile_window", {
      profile: selection()
    });
  }

  async function openProfileWindowForHandle(handle: string) {
    const profile = profiles.find((candidate) => candidate.handle === handle);
    const profileSelection: ProfileSelection = {
      identity: profile?.identity || `rho://id/github/${handle}`,
      rho_home: profile?.rho_home || onboarding?.rho_home
    };
    await invoke("open_profile_window", {
      profile: profileSelection
    });
  }

  async function switchGhProfile() {
    setIsSwitchingGh(true);
    try {
      const result = await invoke<CommandResult>("switch_github_profile", {
        profile: selection()
      });
      setActionResult(formatCommandResult("rho gh switch", result));
      await runChecks();
    } catch (cause) {
      setActionResult(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsSwitchingGh(false);
    }
  }

  async function switchGhHandle(handle: string) {
    setIsSwitchingGh(true);
    try {
      const result = await invoke<CommandResult>("switch_github_profile", {
        profile: {
          identity: `rho://id/github/${handle}`,
          rho_home: onboarding?.rho_home || selectedProfile?.rho_home
        }
      });
      setActionResult(formatCommandResult(`rho gh switch ${handle}`, result));
      await runChecks();
      await refreshProfilesAndOnboarding(handle);
    } catch (cause) {
      setActionResult(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsSwitchingGh(false);
    }
  }

  async function createProfileForHandle(handle: string) {
    const cleanHandle = handle.trim();
    if (!cleanHandle) {
      setOnboardingError("Enter a GitHub handle first.");
      return;
    }
    setIsCreatingProfile(cleanHandle);
    setOnboardingError("");
    try {
      const result = await invoke<CommandResult>("create_github_profile", {
        input: {
          handle: cleanHandle,
          displayName: cleanHandle,
          rhoHome: onboarding?.rho_home
        }
      });
      setActionResult(formatCommandResult(`rho id init ${cleanHandle}`, result));
      setManualHandle("");
      await refreshProfilesAndOnboarding(cleanHandle);
    } catch (cause) {
      setOnboardingError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsCreatingProfile("");
    }
  }

  async function createMissingDetectedProfiles() {
    const missing = onboarding?.gh_accounts.filter((account) => !account.has_rho_profile) ?? [];
    if (missing.length === 0) {
      setOnboardingError("");
      setActionResult("All detected GitHub accounts already have Rho profiles.");
      return;
    }
    setOnboardingError("");
    const results: string[] = [];
    for (const account of missing) {
      setIsCreatingProfile(account.login);
      try {
        const result = await invoke<CommandResult>("create_github_profile", {
          input: {
            handle: account.login,
            displayName: account.login,
            rhoHome: onboarding?.rho_home
          }
        });
        results.push(formatCommandResult(`rho id init ${account.login}`, result));
      } catch (cause) {
        results.push(`${account.login}: ${cause instanceof Error ? cause.message : String(cause)}`);
      }
    }
    setIsCreatingProfile("");
    setActionResult(results.join("\n\n"));
    await refreshProfilesAndOnboarding();
  }

  async function verifyProfileForHandle(handle: string) {
    console.log(`[verify] start handle=${handle} rhoHome=${onboarding?.rho_home ?? "default"}`);
    setIsVerifyingProfile(handle);
    setOnboardingError("");
    try {
      const result = await invoke<CommandResult>("verify_github_profile", {
        handle,
        rhoHome: onboarding?.rho_home
      });
      setActionResult(formatCommandResult(`rho id verify-github ${handle}`, result));
      if (result.ok) {
        console.log(`[verify] ${handle} -> VERIFIED`, result);
        setProofIssue(null);
      } else {
        const text = `${result.stderr}\n${result.stdout}`.toLowerCase();
        const kind =
          text.includes("invalid claim") || text.includes("does not match this key")
            ? "invalid"
            : "missing";
        console.warn(`[verify] ${handle} -> ${kind.toUpperCase()}`, result);
        setProofIssue({ handle, kind });
      }
      await refreshProfilesAndOnboarding(handle);
    } catch (cause) {
      console.error(`[verify] ${handle} -> ERROR`, cause);
      setOnboardingError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsVerifyingProfile("");
    }
  }

  async function bindCommitAuthorForHandle(handle: string) {
    setIsBindingCommitAuthor(handle);
    setOnboardingError("");
    try {
      const result = await invoke<CommandResult>("bind_github_commit_profile", {
        handle,
        rhoHome: onboarding?.rho_home
      });
      setActionResult(formatCommandResult(`bind commit author ${handle}`, result));
      await runChecks();
      await refreshProfilesAndOnboarding(handle);
    } catch (cause) {
      setOnboardingError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsBindingCommitAuthor("");
    }
  }

  async function showProfileForHandle(handle: string) {
    setOnboardingError("");
    try {
      const result = await invoke<CommandResult>("show_github_profile", {
        handle,
        rhoHome: onboarding?.rho_home
      });
      setActionResult(formatCommandResult(`rho id show ${handle}`, result));
    } catch (cause) {
      setOnboardingError(cause instanceof Error ? cause.message : String(cause));
    }
  }

  async function checkProfileEnv() {
    setIsCheckingEnv(true);
    try {
      const result = await invoke<CommandResult>("profile_rho_env", {
        profile: selection()
      });
      setActionResult(formatCommandResult("rho env status", result));
    } catch (cause) {
      setActionResult(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsCheckingEnv(false);
    }
  }

  async function loadProjects(identity = selectedIdentity) {
    setIsLoadingProjects(true);
    setProjectsError("");
    try {
      const result = await invoke<DesktopProject[]>("desktop_projects", {
        profile: selection(identity)
      });
      setProjects(result);
      if (selectedProjectPath && !result.some((project) => project.path === selectedProjectPath)) {
        setSelectedProjectPath("");
        setRepoDetail(null);
      }
    } catch (cause) {
      setProjectsError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsLoadingProjects(false);
    }
  }

  async function addLocalProject() {
    if (!localProjectPath.trim()) {
      setProjectsError("Enter a local repository path first.");
      return;
    }
    setIsAddingProject(true);
    setProjectsError("");
    try {
      const project = await invoke<DesktopProject>("add_local_project", {
        path: localProjectPath,
        profile: selection()
      });
      setActionResult(`Added ${project.name}`);
      setLocalProjectPath("");
      await loadProjects();
      await selectProject(project.path);
    } catch (cause) {
      setProjectsError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsAddingProject(false);
    }
  }

  async function cloneProject() {
    if (!cloneUrl.trim()) {
      setProjectsError("Enter a GitHub repository URL first.");
      return;
    }
    setIsCloningProject(true);
    setProjectsError("");
    try {
      const project = await invoke<DesktopProject>("clone_github_project", {
        url: cloneUrl,
        destination: cloneDestination || undefined,
        profile: selection()
      });
      setActionResult(`Cloned ${project.name}`);
      setCloneUrl("");
      setCloneDestination("");
      await loadProjects();
      await selectProject(project.path);
    } catch (cause) {
      setProjectsError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsCloningProject(false);
    }
  }

  async function setupRhoRepo() {
    if (!setupRepoPath.trim()) {
      setProjectsError("Enter a repository folder path first.");
      return;
    }
    if (!selectedIdentity) {
      setProjectsError("Select a Rho profile before setting up a repo.");
      return;
    }
    setIsSettingUpRhoRepo(true);
    setProjectsError("");
    try {
      const result = await invoke<CommandResult>("setup_rho_repo", {
        input: {
          path: setupRepoPath,
          repoId: setupRepoId || undefined,
          remoteUrl: setupRemoteUrl || undefined,
          profile: selection(),
          protectOwnerInbox: setupProtectOwnerInbox
        }
      });
      setActionResult(formatCommandResult("setup rho repo", result));
      setSetupRepoPath("");
      setSetupRepoId("");
      setSetupRemoteUrl("");
      await loadProjects();
    } catch (cause) {
      setProjectsError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsSettingUpRhoRepo(false);
    }
  }

  async function selectProject(path: string) {
    setSelectedProjectPath(path);
    setRepoDetailError("");
    setIsLoadingRepoDetail(true);
    try {
      const detail = await invoke<RepoDetail>("repo_detail", {
        path,
        profile: selection()
      });
      setRepoDetail(detail);
    } catch (cause) {
      setRepoDetail(null);
      setRepoDetailError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsLoadingRepoDetail(false);
    }
  }

  async function openExternalUrl(url: string) {
    try {
      await invoke("open_external_url", { url });
    } catch (cause) {
      setActionResult(cause instanceof Error ? cause.message : String(cause));
    }
  }

  async function copyValue(value: string, field: string) {
    try {
      await navigator.clipboard.writeText(value);
      setCopiedField(field);
      window.setTimeout(() => setCopiedField((current) => (current === field ? "" : current)), 1500);
    } catch (cause) {
      setActionResult(cause instanceof Error ? cause.message : String(cause));
    }
  }

  function switchToProfile(identity: string) {
    // Full reload bound to the chosen profile (via ?identity=) so there is no
    // leftover in-memory state from the previous profile.
    const url = new URL(window.location.href);
    url.searchParams.set("identity", identity);
    window.location.replace(url.toString());
  }

  function reonboard() {
    setShowProfileSwitcher(false);
    setView("onboarding");
    // Skip the tool check when the dependencies are already satisfied.
    setOnboardingStep(allDependenciesReady ? "accounts" : "tools");
  }

  function toggleTheme() {
    setTheme((current) => (current === "dark" ? "light" : "dark"));
  }

  function removeProfile(identity: string) {
    if (
      !window.confirm(
        "Remove this profile from Rho Desktop? Your keys and identity files are kept on disk — this only hides it here."
      )
    ) {
      return;
    }
    setHiddenProfiles((current) => {
      const next = current.includes(identity) ? current : [...current, identity];
      window.localStorage.setItem("rho.desktop.hiddenProfiles", JSON.stringify(next));
      return next;
    });
  }

  function openProjects() {
    setShowProfileSwitcher(false);
    setView("projects");
  }

  function openSettings() {
    setShowProfileSwitcher(false);
    setView("settings");
  }

  async function openProfileProcess(identity: string) {
    try {
      await invoke("open_profile_process", { identity });
    } catch (cause) {
      setActionResult(cause instanceof Error ? cause.message : String(cause));
    }
  }

  function isAccountSetUp(account: GitHubAccount): boolean {
    return Boolean(
      account.has_rho_profile && account.has_local_private_keys && account.proof_verified
    );
  }

  async function captureScreenshotToClipboard(): Promise<boolean> {
    try {
      const { default: html2canvas } = await import("html2canvas-pro");
      const canvas = await html2canvas(document.body, {
        backgroundColor: null,
        logging: false,
        scale: Math.min(window.devicePixelRatio || 1, 2)
      });
      const blob = await new Promise<Blob | null>((resolve) =>
        canvas.toBlob((value) => resolve(value), "image/png")
      );
      if (!blob || typeof ClipboardItem === "undefined" || !navigator.clipboard?.write) {
        return false;
      }
      await navigator.clipboard.write([new ClipboardItem({ "image/png": blob })]);
      return true;
    } catch {
      return false;
    }
  }

  async function reportBug() {
    const captured = await captureScreenshotToClipboard();
    const recent = (actionResult || error || "none").slice(0, 800);
    const body = [
      "## What happened?",
      "",
      "## Steps to reproduce",
      "1. ",
      "",
      "---",
      captured
        ? "<!-- A screenshot was copied to your clipboard — paste it here with Cmd/Ctrl+V -->"
        : "<!-- Tip: attach a screenshot here -->",
      "",
      "### Context",
      `- Rho Desktop: ${version || "unknown"}`,
      `- Screen: ${onboardingStep}`,
      `- Profile: ${selectedIdentity || "none"}`,
      `- Platform: ${navigator.userAgent}`,
      "",
      "### Last output",
      "```",
      recent,
      "```"
    ].join("\n");
    const url =
      "https://github.com/madhavajay/rho/issues/new" +
      `?title=${encodeURIComponent("[Desktop] ")}` +
      `&body=${encodeURIComponent(body)}`;
    setActionResult(
      captured
        ? "Screenshot copied to clipboard — paste it into the issue with Cmd/Ctrl+V."
        : "Opening bug report (screenshot capture unavailable)."
    );
    void openExternalUrl(url);
  }

  async function signInWithGitHub() {
    setIsOpeningTerminal(true);
    setOnboardingError("");
    try {
      await invoke("open_terminal_command", { command: "gh auth login" });
    } catch (cause) {
      setOnboardingError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsOpeningTerminal(false);
    }
  }

  async function openProjectFolder(path: string) {
    try {
      const result = await invoke<CommandResult>("open_project_folder", { path });
      if (!result.ok) {
        setActionResult(formatCommandResult("open folder", result));
      }
    } catch (cause) {
      setActionResult(cause instanceof Error ? cause.message : String(cause));
    }
  }

  async function runRepoAction(
    action: string,
    overrides: { target?: string; requestId?: string } = {}
  ) {
    if (!repoDetail) {
      return;
    }
    setIsRunningRepoAction(action);
    try {
      const result = await invoke<CommandResult>("run_repo_cli_action", {
        input: {
          path: repoDetail.project.path,
          profile: selection(),
          action,
          target: (overrides.target ?? repoActionTargetHandle) || undefined,
          requestId: (overrides.requestId ?? repoActionRequestId) || undefined
        }
      });
      setActionResult(formatCommandResult(action.replace(/_/g, " "), result));
      await loadProjects();
      await selectProject(repoDetail.project.path);
    } catch (cause) {
      setActionResult(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsRunningRepoAction("");
    }
  }

  async function commitRepoChanges() {
    if (!repoDetail) {
      return;
    }
    if (!commitMessage.trim()) {
      setActionResult("Enter a commit message first.");
      return;
    }
    setIsCommittingRepo(true);
    try {
      const result = await invoke<CommandResult>("commit_repo_changes", {
        input: {
          path: repoDetail.project.path,
          profile: selection(),
          message: commitMessage
        }
      });
      setActionResult(formatCommandResult("rho commit", result));
      setCommitMessage("");
      await loadProjects();
      await selectProject(repoDetail.project.path);
    } catch (cause) {
      setActionResult(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsCommittingRepo(false);
    }
  }

  async function sendProjectMessage() {
    if (!repoDetail) {
      return;
    }
    if (!messageRecipient.trim()) {
      setActionResult("Enter a recipient GitHub handle first.");
      return;
    }
    if (!messageText.trim()) {
      setActionResult("Enter a message first.");
      return;
    }
    setIsSendingMessage(true);
    try {
      const result = await invoke<CommandResult>("send_project_message", {
        input: {
          path: repoDetail.project.path,
          profile: selection(),
          to: messageRecipient,
          thread: messageThread || undefined,
          text: messageText,
          messageType: "chat"
        }
      });
      setActionResult(formatCommandResult("send message", result));
      setMessageThread("");
      setMessageText("");
      await loadProjects();
      await selectProject(repoDetail.project.path);
    } catch (cause) {
      setActionResult(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsSendingMessage(false);
    }
  }

  async function runGitAction(action: string, branch?: string) {
    if (!repoDetail) {
      return;
    }
    setIsRunningGitAction(action);
    try {
      const result = await invoke<CommandResult>("run_git_repo_action", {
        input: {
          path: repoDetail.project.path,
          profile: selection(),
          action,
          branch: (branch ?? branchName) || undefined
        }
      });
      setActionResult(formatCommandResult(action.replace(/_/g, " "), result));
      await loadProjects();
      await selectProject(repoDetail.project.path);
    } catch (cause) {
      setActionResult(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsRunningGitAction("");
    }
  }

  function formatCommandResult(label: string, result: CommandResult): string {
    const body = [result.stdout, result.stderr].filter(Boolean).join("\n");
    const statusText = result.ok ? "ok" : `exit ${result.code ?? "unknown"}`;
    return `${label}: ${statusText}${body ? `\n${body}` : ""}`;
  }

  function shortPath(path: string): string {
    return path.length > 70 ? `...${path.slice(-67)}` : path;
  }

  function profileForHandle(handle: string): DesktopProfile | undefined {
    return profiles.find((profile) => profile.handle === handle);
  }

  function requestIdFromPath(path: string): string {
    return path.split("/").find((part) => part.startsWith("req-")) || "";
  }

  function keysFolder(account: GitHubAccount): string | undefined {
    const file = account.signing_key_path || account.encryption_key_path;
    if (!file) {
      return undefined;
    }
    const idx = Math.max(file.lastIndexOf("/"), file.lastIndexOf("\\"));
    return idx > 0 ? file.slice(0, idx) : undefined;
  }

  const settingsContent = (
    <>
      <header className="window-titlebar">
        <div>
          <h1>Settings</h1>
          <p>Rho Desktop {version}</p>
        </div>
      </header>
      <div className="settings-body">
        <div className="empty-state">
          <h2>No settings yet</h2>
          <p>App settings will live here. For now, manage profiles from the avatar in the sidebar.</p>
        </div>
      </div>
    </>
  );

  const projectsContent = (
    <>
      <header className="window-titlebar">
        <div>
          <h1>Projects</h1>
          <p>Repositories tracked for this profile.</p>
        </div>
      </header>
      <div className="settings-body">
        <div className="empty-state">
          <h2>No projects yet</h2>
          <p>Project management is coming soon.</p>
        </div>
      </div>
    </>
  );

  const profileSwitcherOverlay = showProfileSwitcher ? (
    <div className="modal-backdrop" onClick={() => setShowProfileSwitcher(false)}>
      <div className="modal-panel" onClick={(event) => event.stopPropagation()}>
        <div className="modal-head">
          <h2>Profiles</h2>
          <button type="button" onClick={() => setShowProfileSwitcher(false)}>
            Close
          </button>
        </div>
        <div className="switcher-list">
          {profiles
            .filter((profile) => !hiddenProfiles.includes(profile.identity))
            .map((profile) => (
              <div
                key={profile.identity}
                className="switcher-row"
                data-current={profile.identity === selectedIdentity}
              >
                <Avatar login={profile.handle} size={38} />
                <div className="switcher-info">
                  <strong>{profile.handle}</strong>
                  <span>{profile.identity}</span>
                </div>
                {profile.identity === selectedIdentity ? (
                  <span className="switcher-current">current</span>
                ) : null}
                <div className="switcher-actions">
                  <button
                    type="button"
                    onClick={() => switchToProfile(profile.identity)}
                    disabled={profile.identity === selectedIdentity}
                  >
                    Switch
                  </button>
                  <button type="button" onClick={() => void openProfileProcess(profile.identity)}>
                    New Window
                  </button>
                  <button
                    type="button"
                    onClick={() => removeProfile(profile.identity)}
                    disabled={profile.identity === selectedIdentity}
                  >
                    Remove
                  </button>
                </div>
              </div>
            ))}
          {profiles.filter((profile) => !hiddenProfiles.includes(profile.identity)).length === 0 ? (
            <p className="guide-muted">No local profiles yet.</p>
          ) : null}
        </div>
        <div className="modal-foot">
          <button type="button" onClick={reonboard}>
            Set up another profile
          </button>
        </div>
      </div>
    </div>
  ) : null;

  return (
    <main className="app-shell desktop-wallpaper">
      {profileSwitcherOverlay}
      <section className="desktop-window">
        <AppRail
          active={shouldShowOnboarding ? "setup" : view}
          onReportBug={reportBug}
          onOpenSettings={openSettings}
          onOpenProfiles={() => setShowProfileSwitcher(true)}
          onOpenProjects={openProjects}
          onToggleTheme={toggleTheme}
          theme={theme}
          currentLogin={selectedHandle}
        />

        <section className="onboarding-workspace">
          {status !== "ready" ? (
            <header className="window-titlebar">
              <div>
                <h1>Rho Desktop</h1>
                <p>{status === "error" ? error : "Loading desktop state."}</p>
              </div>
            </header>
          ) : !shouldShowOnboarding ? (
            view === "settings" ? (
              settingsContent
            ) : (
              projectsContent
            )
          ) : (
            <>
              <header className="window-titlebar">
                <div>
                  <h1>
                    {onboardingStep === "tools"
                      ? "Set up Rho Desktop"
                      : onboardingStep === "accounts"
                        ? "Choose a GitHub account"
                        : "Prepare your profile"}
                  </h1>
                  <p>
                    {onboardingStep === "tools"
                      ? "Step 1: check required command line tools before creating or opening a profile."
                      : onboardingStep === "accounts"
                        ? "Step 2: pick a detected GitHub account, or sign in with another."
                        : "Step 3: finish setting up the selected account."}
                  </p>
                </div>
              </header>

              {onboardingStep === "tools" ? (
            <div className="dependency-screen">
              {dependenciesError ? <p className="error">{dependenciesError}</p> : null}

              <section className="dependency-panel">
                <div className="dependency-list" aria-label="Dependencies">
                  {visibleDependencies.map((dependency) => (
                    <button
                      key={dependency.name}
                      type="button"
                      className="dependency-item"
                      data-active={selectedDependency?.name === dependency.name}
                      data-state={dependency.status}
                      onClick={() => setSelectedDependencyName(dependency.name)}
                    >
                      <span className="dependency-dot" aria-hidden="true" />
                      <span className="dependency-item-name">{dependencyTitle(dependency.name)}</span>
                      <span className="dependency-item-status">{statusLabel(dependency.status)}</span>
                    </button>
                  ))}
                  {visibleDependencies.length === 0 ? (
                    <div className="empty-state">
                      <h2>No dependencies loaded</h2>
                      <p>Click Check Again to reload the dependency manifest.</p>
                    </div>
                  ) : null}
                </div>

                <div className="dependency-detail">
                  {selectedDependency ? (
                    <>
                      <div className="dependency-detail-heading">
                        <div>
                          <h2>{dependencyTitle(selectedDependency.name)}</h2>
                          <p>{selectedDependency.description}</p>
                        </div>
                        <span data-state={selectedDependency.status}>
                          {statusLabel(selectedDependency.status)}
                        </span>
                      </div>

                      <dl className="dependency-facts">
                        <div>
                          <dt>Path</dt>
                          <dd>{selectedDependency.path || "Not found"}</dd>
                        </div>
                        <div>
                          <dt>Version</dt>
                          <dd>{selectedDependency.version || selectedDependency.detail}</dd>
                        </div>
                        {selectedDependency.website ? (
                          <div>
                            <dt>Website</dt>
                            <dd>
                              <a
                                href={selectedDependency.website}
                                className="dependency-link"
                                onClick={(event) => {
                                  event.preventDefault();
                                  void openExternalUrl(selectedDependency.website!);
                                }}
                              >
                                {selectedDependency.website}
                              </a>
                            </dd>
                          </div>
                        ) : null}
                      </dl>

                      <div className="install-command-list">
                        <h2>Install Options</h2>
                        {selectedDependency.install_commands.map((command) => (
                          <code key={command}>{command}</code>
                        ))}
                        {selectedDependency.install_commands.length === 0 ? (
                          <p>No install command is configured for this platform.</p>
                        ) : null}
                      </div>
                    </>
                  ) : (
                    <div className="empty-state">
                      <h2>Select a dependency</h2>
                      <p>Dependency details will appear here.</p>
                    </div>
                  )}
                </div>
              </section>

              <div className="stage-actions split-actions">
                <button
                  type="button"
                  onClick={() => void refreshDependencies()}
                  disabled={isCheckingDependencies}
                >
                  {isCheckingDependencies ? "Checking" : "Check Again"}
                </button>
                {!allDependenciesReady ? (
                  <button
                    type="button"
                    onClick={() => {
                      setToolsSkipped(true);
                      setOnboardingStep("accounts");
                    }}
                  >
                    Skip
                  </button>
                ) : null}
                <button
                  type="button"
                  className="primary-action"
                  disabled={!allDependenciesReady}
                  onClick={() => {
                    setToolsSkipped(false);
                    setOnboardingStep("accounts");
                  }}
                >
                  Continue
                </button>
              </div>
            </div>
            ) : onboardingStep === "accounts" ? (
            <div className="dependency-screen">
              <div className="accounts-screen">
                {toolsSkipped ? (
                  <p className="error">
                    You skipped the tool check. If account actions fail, go back and confirm Git and
                    the GitHub CLI are installed.
                  </p>
                ) : null}
                {onboardingError ? <p className="error">{onboardingError}</p> : null}

                {onboarding && onboarding.gh_accounts.length > 0 ? (
                  (() => {
                    const setUp = onboarding.gh_accounts.filter(isAccountSetUp);
                    const available = onboarding.gh_accounts.filter(
                      (account) => !isAccountSetUp(account)
                    );
                    return (
                      <>
                        {setUp.length > 0 ? (
                          <>
                            <div className="accounts-section-label">Already set up</div>
                            <div className="account-pick-list">
                              {setUp.map((account) => (
                                <div
                                  key={`${account.host}-${account.login}`}
                                  className="account-pick account-pick-static"
                                  data-state="ready"
                                >
                                  <Avatar login={account.login} size={40} />
                                  <span className="account-pick-info">
                                    <strong>{account.login}</strong>
                                    <span>Rho profile ready{account.active ? " · active in gh" : ""}</span>
                                  </span>
                                  <span className="account-pick-status">ready</span>
                                </div>
                              ))}
                            </div>
                            <div className="accounts-divider" />
                          </>
                        ) : null}

                        <div className="accounts-section-label">Choose a GitHub account</div>
                        {available.length > 0 ? (
                          <div className="account-pick-list">
                            {available.map((account) => (
                              <button
                                key={`${account.host}-${account.login}`}
                                type="button"
                                className="account-pick"
                                data-state={isAccountReady(account) ? "ready" : "setup"}
                                onClick={() => {
                                  chooseAccount(account);
                                  setOnboardingStep("profile");
                                }}
                              >
                                <Avatar login={account.login} size={40} />
                                <span className="account-pick-info">
                                  <strong>{account.login}</strong>
                                  <span>
                                    {account.has_rho_profile
                                      ? "Rho profile ready"
                                      : "No Rho profile yet"}
                                    {account.active ? " · active in gh" : ""}
                                  </span>
                                </span>
                                <span className="account-pick-status">
                                  {isAccountReady(account) ? "ready" : "needs setup"}
                                </span>
                                <span className="account-pick-chevron" aria-hidden="true">
                                  ›
                                </span>
                              </button>
                            ))}
                          </div>
                        ) : (
                          <div className="accounts-empty-available">
                            <p>All detected accounts are already set up.</p>
                            <p>To add another, run:</p>
                            <div className="copy-field">
                              <code>gh auth login</code>
                              <button
                                type="button"
                                className="copy-btn"
                                title="Copy command"
                                onClick={() => void copyValue("gh auth login", "gh-login")}
                              >
                                <ClipboardIcon copied={copiedField === "gh-login"} />
                              </button>
                            </div>
                            <p>
                              Then come back here and press Refresh once you have authed a new
                              account.
                            </p>
                          </div>
                        )}
                        <button
                          type="button"
                          className="account-add"
                          onClick={() => void signInWithGitHub()}
                          disabled={isOpeningTerminal}
                        >
                          {isOpeningTerminal ? "Opening Terminal…" : "Run: gh auth login"}
                        </button>
                      </>
                    );
                  })()
                ) : (
                  <div className="empty-state">
                    <h2>No GitHub accounts found</h2>
                    <p>
                      Sign in with the GitHub CLI to create or log in to an account, then refresh.
                    </p>
                    <div className="empty-actions">
                      <button
                        type="button"
                        className="primary-action"
                        onClick={() => void signInWithGitHub()}
                        disabled={isOpeningTerminal}
                      >
                        {isOpeningTerminal ? "Opening Terminal…" : "Sign in with GitHub"}
                      </button>
                    </div>
                  </div>
                )}
              </div>

              <div className="stage-actions split-actions">
                {!allDependenciesReady ? (
                  <button
                    type="button"
                    style={{ marginRight: "auto" }}
                    onClick={() => setOnboardingStep("tools")}
                  >
                    Back
                  </button>
                ) : null}
                <button
                  type="button"
                  onClick={() => void refreshProfilesAndOnboarding()}
                  disabled={isLoadingOnboarding}
                >
                  {isLoadingOnboarding ? "Refreshing" : "Refresh"}
                </button>
              </div>
            </div>
            ) : (
            <div className="dependency-screen">
              <div className="accounts-screen">
                {onboardingError ? <p className="error">{onboardingError}</p> : null}
                {selectedAccount ? (
                  <div className="profile-prepare">
                    <div className="profile-prepare-head">
                      <Avatar login={selectedAccount.login} size={44} />
                      <div className="profile-prepare-id">
                        <strong>{selectedAccount.login}</strong>
                        <span>{selectedAccount.matching_identity}</span>
                      </div>
                    </div>

                    {!selectedAccount.has_rho_profile ? (
                      <div className="guide-callout">
                        <p>Create your Rho profile to generate keys and your GitHub proof.</p>
                        <button
                          type="button"
                          className="primary-action"
                          onClick={() => void createProfileForHandle(selectedAccount.login)}
                          disabled={isCreatingProfile === selectedAccount.login}
                        >
                          {isCreatingProfile === selectedAccount.login
                            ? "Creating…"
                            : "Create Rho Profile"}
                        </button>
                      </div>
                    ) : null}

                    <ol className="guide-steps">
                      <li className="guide-step" data-ok={true}>
                        <span className="guide-step-num">✓</span>
                        <div className="guide-step-body">
                          <h3>Your Rho identity</h3>
                          <p>This is globally unique, derived from your GitHub handle.</p>
                          <div className="copy-field">
                            <code>{selectedAccount.matching_identity}</code>
                            <button
                              type="button"
                              className="copy-btn"
                              title="Copy identity"
                              onClick={() =>
                                void copyValue(selectedAccount.matching_identity, "identity")
                              }
                            >
                              <ClipboardIcon copied={copiedField === "identity"} />
                            </button>
                          </div>
                        </div>
                      </li>

                      <li className="guide-step" data-ok={selectedAccount.has_local_private_keys}>
                        <span className="guide-step-num">
                          {selectedAccount.has_local_private_keys ? "✓" : "2"}
                        </span>
                        <div className="guide-step-body">
                          <h3>Private keys</h3>
                          <p>
                            We generated your signing (Ed25519) and encryption (X25519) keys. They
                            stay on this machine and are never shared.
                          </p>
                          {keysFolder(selectedAccount) ? (
                            <button
                              type="button"
                              className="guide-folder"
                              onClick={() => void openProjectFolder(keysFolder(selectedAccount)!)}
                            >
                              <FolderIcon />
                              <span>{keysFolder(selectedAccount)}</span>
                            </button>
                          ) : (
                            <p className="guide-muted">
                              Keys appear here once your Rho profile is created.
                            </p>
                          )}
                        </div>
                      </li>

                      <li
                        className="guide-step"
                        data-ok={selectedAccount.proof_verified}
                        data-missing={
                          !selectedAccount.proof_verified &&
                          proofIssue?.handle === selectedAccount.login
                        }
                      >
                        <span className="guide-step-num">
                          {selectedAccount.proof_verified
                            ? "✓"
                            : !selectedAccount.proof_verified &&
                                proofIssue?.handle === selectedAccount.login
                              ? "✕"
                              : "3"}
                        </span>
                        <div className="guide-step-body">
                          <h3>
                            GitHub proof
                            {selectedAccount.proof_verified ? (
                              <span className="guide-ok-pill">verified</span>
                            ) : proofIssue?.handle === selectedAccount.login ? (
                              <span className="guide-missing-pill">
                                {proofIssue.kind === "invalid" ? "invalid" : "missing"}
                              </span>
                            ) : null}
                          </h3>
                          <p>
                            To prove you hold this private key, publish this proof on your public
                            GitHub profile — paste it into your bio, website, or social links.
                            Anywhere on the page works. Then click Re-verify.
                          </p>
                          {selectedAccount.proof_url ? (
                            <div className="copy-field">
                              <code>{selectedAccount.proof_url}</code>
                              <button
                                type="button"
                                className="copy-btn"
                                title="Copy proof"
                                onClick={() => void copyValue(selectedAccount.proof_url!, "proof")}
                              >
                                <ClipboardIcon copied={copiedField === "proof"} />
                              </button>
                            </div>
                          ) : (
                            <p className="guide-muted">
                              Your proof appears once your Rho profile is created.
                            </p>
                          )}
                          <div className="guide-actions">
                            <button
                              type="button"
                              onClick={() =>
                                void openExternalUrl(`https://github.com/${selectedAccount.login}`)
                              }
                            >
                              Open GitHub Profile
                            </button>
                            <button
                              type="button"
                              className="primary-action verify-button"
                              data-loading={isVerifyingProfile === selectedAccount.login}
                              onClick={() => void verifyProfileForHandle(selectedAccount.login)}
                              disabled={
                                !selectedAccount.has_rho_profile ||
                                isVerifyingProfile === selectedAccount.login
                              }
                            >
                              {isVerifyingProfile === selectedAccount.login ? (
                                <span className="btn-spinner" aria-label="Checking" />
                              ) : (
                                "Re-verify"
                              )}
                            </button>
                          </div>
                        </div>
                      </li>
                    </ol>
                  </div>
                ) : (
                  <div className="empty-state">
                    <h2>No account selected</h2>
                    <p>Go back and pick a GitHub account.</p>
                  </div>
                )}
              </div>

              <div className="stage-actions split-actions">
                <button
                  type="button"
                  style={{ marginRight: "auto" }}
                  onClick={() => setOnboardingStep("accounts")}
                >
                  Back
                </button>
                <button type="button" className="primary-action" onClick={finishOnboarding}>
                  Finish
                </button>
              </div>
            </div>
            )}
            </>
          )}
        </section>
      </section>
    </main>
  );

}
