// @ts-nocheck
import type { CSSProperties } from "react";
import { useEffect, useState } from "react";
import { openWorldshaperStudioWindow } from "../shared/windowing";
import launcherBackground from "../../background.png";
import { LauncherAdminPanel } from "./components/LauncherAdminPanel";
import { LauncherLogsModal } from "./components/LauncherLogsModal";
import { LauncherNewsPanel } from "./components/LauncherNewsPanel";
import { LauncherPublicRequestBoard } from "./components/LauncherPublicRequestBoard";
import { useLauncherRequestBoard } from "./useLauncherRequestBoard";

declare const __APP_BUILD__: string;

type WorldDefaultPayload = {
  worldId?: string;
  world?: {
    id?: string;
  };
};

type LaunchState = "ready" | "opening" | "opened" | "blocked" | "error";
type BoardTab = "news" | "requests";
type LauncherWindowMode = "public" | "admin";
type LauncherRequestStatus = "pending" | "active" | "implemented";
type AdminDetailTab = "routing" | "analysis";

type LauncherRequestAnalysisRouting = {
  summary?: string;
  ambiguity?: "low" | "medium" | "high";
  matchedTerms?: string[];
  suggestedTags?: string[];
  suggestedSystems?: string[];
  suggestedModules?: string[];
  rationale?: string;
  possibleDirections?: string[];
  kbSections?: string[];
};

type LauncherRequest = {
  id: string;
  sourceSubmissionId?: string;
  title: string;
  status: LauncherRequestStatus;
  category: string;
  tags: string[];
  sourceText: string;
  summary: string;
  implementationNotes: string;
  analysis?: {
    state?: "unprocessed" | "processing" | "processed" | "needs_review" | "error";
    confidence?: number | null;
    model?: string;
    createdAt?: string;
    updatedAt?: string;
    error?: string;
    submissionId?: string;
    sourceTextSnapshot?: string;
    routing?: LauncherRequestAnalysisRouting;
    itemCount?: number;
    items?: Array<{
      title?: string;
      primaryCategory?: string;
      tags?: string[];
      statusRecommendation?: string;
      parsedInterpretation?: string;
      implementationApproach?: string;
      affectedSystems?: string[];
      affectedFiles?: string[];
      problemType?: string;
      rawExcerpt?: string;
      confidence?: number | null;
      reviewRationale?: string;
      reviewOptions?: string[];
      notes?: string;
    }>;
  };
  createdAt: string;
  updatedAt: string;
};

type LauncherRequestAnalysisItem = NonNullable<NonNullable<LauncherRequest["analysis"]>["items"]>[number];

type LauncherRequestsPayload = {
  requests?: LauncherRequest[];
};

type RecentSaveEvent = {
  at?: string;
  type?: string;
  requestId?: string;
  textPreview?: string;
  status?: string;
  category?: string;
  itemCount?: number;
  model?: string;
  reason?: string;
  provider?: string;
  pid?: number;
  code?: number | null;
  signal?: string;
  error?: string;
};

type RecentSaveEventsPayload = {
  saves?: RecentSaveEvent[];
};

type ProcessPendingPayload = {
  ok?: boolean;
  launched?: boolean;
  reason?: string;
  autorunEnabled?: boolean;
  configured?: boolean;
  queuedPendingCount?: number;
  pid?: number;
};

type RequeueAnalysisPayload = {
  ok?: boolean;
  launched?: boolean;
  reason?: string;
  request?: LauncherRequest;
  requests?: LauncherRequest[];
  requestId?: string;
  queuedPendingCount?: number;
  pid?: number;
};

type LauncherRequestMetaPayload = {
  allowedTags?: string[];
};

type AdminAuthPayload = {
  ok?: boolean;
  accessGranted?: boolean;
  adminConfigured?: boolean;
  error?: string;
};

const DEFAULT_EDITOR_WORLD_ID_FALLBACK = "overworld";

function readLauncherWindowMode(): LauncherWindowMode {
  if (typeof window === "undefined") {
    return "public";
  }
  const searchParams = new URLSearchParams(window.location.search);
  return searchParams.get("admin") === "requests" ? "admin" : "public";
}

function normalizeStringList(values: string[]): string[] {
  return Array.from(new Set(
    values
      .map((entry) => String(entry || "").trim())
      .filter(Boolean),
  )).sort((left, right) => left.localeCompare(right));
}

function appendUniqueString(values: string[], value: string): string[] {
  const normalizedValue = String(value || "").trim();
  if (!normalizedValue) {
    return normalizeStringList(values);
  }
  return normalizeStringList([...values, normalizedValue]);
}

function removeStringValue(values: string[], value: string): string[] {
  const normalizedValue = String(value || "").trim().toLowerCase();
  return normalizeStringList(values.filter((entry) => entry.trim().toLowerCase() !== normalizedValue));
}

function toggleStringSelection(current: string[], value: string): string[] {
  return current.includes(value)
    ? current.filter((entry) => entry !== value)
    : [...current, value].sort((left, right) => left.localeCompare(right));
}

function normalizeSearchText(value: string): string {
  return String(value || "").replace(/\s+/g, " ").trim().toLowerCase();
}

function extractRoutingTerms(requestEntry: LauncherRequest): string[] {
  const tagTerms = requestEntry.tags
    .map((entry) => String(entry || "").trim())
    .filter(Boolean);
  if (tagTerms.length > 0) {
    return tagTerms.slice(0, 6);
  }
  const seen = new Set<string>();
  const stopWords = new Set([
    "the", "and", "for", "with", "that", "this", "from", "into", "have", "need",
    "want", "make", "more", "just", "like", "does", "dont", "cannot", "should",
    "would", "could", "about", "because", "there", "their", "they", "them", "then",
    "than", "over", "under", "your", "while", "where",
  ]);
  const matches = `${requestEntry.title} ${requestEntry.sourceText}`.match(/[A-Za-z][A-Za-z0-9/-]{2,}/g) || [];
  return matches
    .map((entry) => entry.trim())
    .filter((entry) => {
      const normalized = entry.toLowerCase();
      if (stopWords.has(normalized) || seen.has(normalized)) {
        return false;
      }
      seen.add(normalized);
      return true;
    })
    .slice(0, 6);
}

function buildRoutingSummaryFallback(requestEntry: LauncherRequest, firstItem: LauncherRequestAnalysisItem | null): string {
  const normalizedSummary = String(requestEntry.summary || "").trim();
  if (normalizedSummary && normalizedSummary !== "Awaiting parsing and categorization.") {
    return normalizedSummary;
  }
  if (firstItem?.parsedInterpretation) {
    return String(firstItem.parsedInterpretation).trim();
  }
  const normalizedSource = String(requestEntry.sourceText || "").replace(/\s+/g, " ").trim();
  if (normalizedSource) {
    return normalizedSource.length > 220
      ? `${normalizedSource.slice(0, 217).trim()}...`
      : normalizedSource;
  }
  return "No routing summary has been stored yet.";
}

function buildFallbackRouting(requestEntry: LauncherRequest): LauncherRequestAnalysisRouting {
  const firstItem = Array.isArray(requestEntry.analysis?.items) ? requestEntry.analysis.items[0] : null;
  const routedTags = Array.isArray(firstItem?.tags) && firstItem.tags.length > 0
    ? firstItem.tags
    : requestEntry.tags.length > 0
      ? requestEntry.tags
      : (requestEntry.category && requestEntry.category !== "Unsorted" ? [requestEntry.category] : []);
  const likelySystems = Array.isArray(firstItem?.affectedSystems) && firstItem.affectedSystems.length > 0
    ? firstItem.affectedSystems
    : (routedTags.length > 0 ? routedTags : []);
  const possibleDirections = Array.isArray(firstItem?.reviewOptions) && firstItem.reviewOptions.length > 0
    ? firstItem.reviewOptions
    : (requestEntry.implementationNotes.trim() ? [requestEntry.implementationNotes.trim()] : []);
  return {
    summary: buildRoutingSummaryFallback(requestEntry, firstItem),
    ambiguity: requestEntry.status === "pending" ? "medium" : "low",
    matchedTerms: extractRoutingTerms(requestEntry),
    suggestedTags: Array.isArray(routedTags) ? routedTags : [],
    suggestedSystems: likelySystems,
    suggestedModules: [],
    rationale: String(
      firstItem?.reviewRationale
      || requestEntry.implementationNotes
      || `Routing was reconstructed from the saved request title, tags, and submission text for "${requestEntry.title}".`
    ).trim(),
    possibleDirections,
    kbSections: [],
  };
}

function mergeRoutingWithFallback(
  requestEntry: LauncherRequest,
  existingRouting: LauncherRequestAnalysisRouting | undefined,
): LauncherRequestAnalysisRouting {
  const fallbackRouting = buildFallbackRouting(requestEntry);
  const normalizedRouting = existingRouting || {};
  return {
    summary: String(normalizedRouting.summary || "").trim() || fallbackRouting.summary,
    ambiguity: normalizedRouting.ambiguity || fallbackRouting.ambiguity,
    matchedTerms: Array.isArray(normalizedRouting.matchedTerms) && normalizedRouting.matchedTerms.length > 0
      ? normalizedRouting.matchedTerms
      : fallbackRouting.matchedTerms,
    suggestedTags: Array.isArray(normalizedRouting.suggestedTags) && normalizedRouting.suggestedTags.length > 0
      ? normalizedRouting.suggestedTags
      : fallbackRouting.suggestedTags,
    suggestedSystems: Array.isArray(normalizedRouting.suggestedSystems) && normalizedRouting.suggestedSystems.length > 0
      ? normalizedRouting.suggestedSystems
      : fallbackRouting.suggestedSystems,
    suggestedModules: Array.isArray(normalizedRouting.suggestedModules) && normalizedRouting.suggestedModules.length > 0
      ? normalizedRouting.suggestedModules
      : fallbackRouting.suggestedModules,
    rationale: String(normalizedRouting.rationale || "").trim() || fallbackRouting.rationale,
    possibleDirections: Array.isArray(normalizedRouting.possibleDirections) && normalizedRouting.possibleDirections.length > 0
      ? normalizedRouting.possibleDirections
      : fallbackRouting.possibleDirections,
    kbSections: Array.isArray(normalizedRouting.kbSections) && normalizedRouting.kbSections.length > 0
      ? normalizedRouting.kbSections
      : fallbackRouting.kbSections,
  };
}

function hydrateLauncherRequestForUi(requestEntry: LauncherRequest): LauncherRequest {
  const nextRequest = cloneLauncherRequest(requestEntry);
  nextRequest.analysis = {
    ...(nextRequest.analysis || {}),
    createdAt: nextRequest.analysis?.createdAt || nextRequest.createdAt,
    updatedAt: nextRequest.analysis?.updatedAt || nextRequest.updatedAt,
    itemCount: nextRequest.analysis?.itemCount ?? (Array.isArray(nextRequest.analysis?.items) ? nextRequest.analysis?.items.length : 0),
    items: Array.isArray(nextRequest.analysis?.items) ? nextRequest.analysis.items : [],
    routing: mergeRoutingWithFallback(nextRequest, nextRequest.analysis?.routing),
  };
  return nextRequest;
}

function buildRequestSearchCorpus(requestEntry: LauncherRequest): string {
  return normalizeSearchText([
    requestEntry.title,
    requestEntry.category,
    requestEntry.tags.join(" "),
    requestEntry.sourceText,
    requestEntry.summary,
    requestEntry.implementationNotes,
    requestEntry.analysis?.routing?.summary,
    requestEntry.analysis?.routing?.rationale,
    ...(Array.isArray(requestEntry.analysis?.routing?.matchedTerms) ? requestEntry.analysis?.routing?.matchedTerms : []),
    ...(Array.isArray(requestEntry.analysis?.items)
      ? requestEntry.analysis.items.flatMap((item) => [
        item.title,
        item.primaryCategory,
        item.parsedInterpretation,
        item.implementationApproach,
        ...(Array.isArray(item.tags) ? item.tags : []),
      ])
      : []),
  ].filter(Boolean).join(" "));
}

function matchesRequestFilterToken(requestEntry: LauncherRequest, token: string): boolean {
  if (token === "pending") {
    return requestEntry.status === "pending";
  }
  if (token === "queued") {
    return isQueuedPendingRequest(requestEntry);
  }
  if (token === "review") {
    return isNeedsReviewRequest(requestEntry);
  }
  if (token === "active") {
    return requestEntry.status === "active";
  }
  if (token === "implemented") {
    return requestEntry.status === "implemented";
  }
  return false;
}

function requestMatchesFilters(
  requestEntry: LauncherRequest,
  searchText: string,
  statusSelections: string[],
  tagSelections: string[],
): boolean {
  const normalizedSearchText = normalizeSearchText(searchText);
  if (normalizedSearchText && !buildRequestSearchCorpus(requestEntry).includes(normalizedSearchText)) {
    return false;
  }
  if (statusSelections.length > 0 && !statusSelections.some((token) => matchesRequestFilterToken(requestEntry, token))) {
    return false;
  }
  if (tagSelections.length > 0 && !tagSelections.some((tag) => requestEntry.tags.includes(tag))) {
    return false;
  }
  return true;
}

function FilterIcon() {
  return (
    <svg viewBox="0 0 24 24" aria-hidden="true">
      <path d="M4 6h16M7 12h10M10 18h4" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
    </svg>
  );
}

function LogsIcon() {
  return (
    <svg viewBox="0 0 24 24" aria-hidden="true">
      <path d="M5 5h14v14H5z" fill="none" stroke="currentColor" strokeWidth="1.8" />
      <path d="M8 9h8M8 12h8M8 15h5" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
    </svg>
  );
}

function SaveIcon() {
  return (
    <svg viewBox="0 0 24 24" aria-hidden="true">
      <path d="M5 4h11l3 3v13H5z" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round" />
      <path d="M8 4h7v5H8zM8 14h8v5H8z" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round" />
    </svg>
  );
}

function CheckIcon() {
  return (
    <svg viewBox="0 0 24 24" aria-hidden="true">
      <path d="M5 12.5l4.2 4.2L19 7" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

function PlayIcon() {
  return (
    <svg viewBox="0 0 24 24" aria-hidden="true">
      <path d="M8 6l10 6-10 6z" fill="currentColor" />
    </svg>
  );
}

type LauncherChipSelectorProps = {
  label: string;
  values: string[];
  options: string[];
  placeholder: string;
  emptyLabel?: string;
  onAdd: (value: string) => void;
  onRemove: (value: string) => void;
};

function LauncherChipSelector({
  label,
  values,
  options,
  placeholder,
  emptyLabel = "No tags selected yet.",
  onAdd,
  onRemove,
}: LauncherChipSelectorProps) {
  const availableOptions = options.filter((option) => !values.includes(option));
  return (
    <div className="launcher-chip-field">
      <div className="launcher-chip-field-head">
        <span className="launcher-request-filter-label">{label}</span>
        <select
          className="launcher-request-filter-select"
          value=""
          onChange={(event) => {
            const nextValue = event.target.value;
            if (!nextValue) {
              return;
            }
            onAdd(nextValue);
          }}
          disabled={availableOptions.length === 0}
        >
          <option value="">{availableOptions.length > 0 ? placeholder : "Everything added"}</option>
          {availableOptions.map((option) => (
            <option key={`${label}-${option}`} value={option}>{option}</option>
          ))}
        </select>
      </div>
      <div className="launcher-chip-list">
        {values.length > 0 ? values.map((value) => (
          <span key={`${label}-${value}`} className="launcher-chip">
            <span>{value}</span>
            <button
              type="button"
              className="launcher-chip-remove"
              onClick={() => onRemove(value)}
              aria-label={`Remove ${value}`}
              title={`Remove ${value}`}
            >
              x
            </button>
          </span>
        )) : (
          <span className="launcher-chip-empty">{emptyLabel}</span>
        )}
      </div>
    </div>
  );
}

async function resolveDefaultWorldId(): Promise<string> {
  const response = await fetch("/api/world-default");
  if (!response.ok) {
    throw new Error(`Failed to load default world (${response.status}).`);
  }
  const payload = await response.json() as WorldDefaultPayload;
  const resolvedWorldId = String(payload.worldId || payload.world?.id || "").trim();
  return resolvedWorldId || DEFAULT_EDITOR_WORLD_ID_FALLBACK;
}

async function fetchJsonOrThrow<T>(input: RequestInfo | URL, init?: RequestInit): Promise<T> {
  const response = await fetch(input, init);
  if (!response.ok) {
    let detail = `Request failed (${response.status}).`;
    try {
      const payload = await response.json() as { error?: string };
      detail = String(payload?.error || detail);
    } catch {
      // Ignore JSON parse failures and fall back to status text.
    }
    throw new Error(detail);
  }
  return response.json() as Promise<T>;
}

function buildAdminHeaders(password: string, headers?: HeadersInit): HeadersInit {
  const normalizedPassword = String(password || "").trim();
  if (!normalizedPassword) {
    return {
      ...(headers || {}),
    };
  }
  return {
    ...(headers || {}),
    "x-worldshaper-admin-password": normalizedPassword,
  };
}

function isAdminAccessError(error: unknown): boolean {
  const text = String(error || "").toLowerCase();
  return text.includes("admin access denied")
    || text.includes("admin access is not configured");
}

function cloneLauncherRequest(requestEntry: LauncherRequest): LauncherRequest {
  return JSON.parse(JSON.stringify(requestEntry)) as LauncherRequest;
}

function formatRequestTimestamp(value: string): string {
  const parsed = Date.parse(String(value || ""));
  if (!Number.isFinite(parsed)) {
    return "Saved recently";
  }
  return new Intl.DateTimeFormat(undefined, {
    month: "short",
    day: "numeric",
    hour: "numeric",
    minute: "2-digit",
  }).format(parsed);
}

function formatRequestSubmittedDate(value: string): string {
  const parsed = Date.parse(String(value || ""));
  if (!Number.isFinite(parsed)) {
    return "Recently";
  }
  return new Intl.DateTimeFormat(undefined, {
    month: "short",
    day: "numeric",
    year: "numeric",
  }).format(parsed);
}

function normalizeAnalysisState(value: string | undefined): string {
  return String(value || "").trim().toLowerCase();
}

function formatAnalysisStateLabel(value: string | undefined): string {
  const normalized = normalizeAnalysisState(value);
  if (normalized === "processing") {
    return "Processing";
  }
  if (normalized === "processed") {
    return "Processed";
  }
  if (normalized === "needs_review") {
    return "Needs Review";
  }
  if (normalized === "error") {
    return "Error";
  }
  return "Unprocessed";
}

function getRequestDisplayStateLabel(requestEntry: LauncherRequest): string {
  if (requestEntry.status === "implemented") {
    return "Implemented";
  }
  if (requestEntry.status === "active") {
    return "Active";
  }
  const analysisState = normalizeAnalysisState(requestEntry.analysis?.state);
  if (!analysisState || analysisState === "unprocessed") {
    return "Queued";
  }
  if (analysisState === "needs_review") {
    return "Needs Review";
  }
  if (analysisState === "error") {
    return "Analysis Error";
  }
  if (analysisState === "processed") {
    return "Reviewed";
  }
  return formatAnalysisStateLabel(analysisState);
}

function getRequestDisplayStateClassName(requestEntry: LauncherRequest): string {
  if (requestEntry.status === "implemented") {
    return "implemented";
  }
  if (requestEntry.status === "active") {
    return "active";
  }
  const analysisState = normalizeAnalysisState(requestEntry.analysis?.state);
  if (!analysisState || analysisState === "unprocessed") {
    return "queued";
  }
  if (analysisState === "needs_review") {
    return "needs-review";
  }
  if (analysisState === "error") {
    return "error";
  }
  if (analysisState === "processed") {
    return "processed";
  }
  if (analysisState === "processing") {
    return "processing";
  }
  return "pending";
}

function isQueuedPendingRequest(requestEntry: LauncherRequest): boolean {
  const analysisState = normalizeAnalysisState(requestEntry.analysis?.state);
  return requestEntry.status === "pending" && (!analysisState || analysisState === "unprocessed" || analysisState === "processing");
}

function isNeedsReviewRequest(requestEntry: LauncherRequest): boolean {
  const analysisState = normalizeAnalysisState(requestEntry.analysis?.state);
  return requestEntry.status === "pending" && (analysisState === "needs_review" || analysisState === "error");
}

function formatEventLabel(event: RecentSaveEvent): string {
  switch (String(event.type || "").trim()) {
    case "launcher-request-add":
      return "Request submitted";
    case "launcher-request-delete":
      return "Request deleted";
    case "launcher-request-update":
      return "Request updated";
    case "launcher-request-review":
      return "Analysis saved for review";
    case "launcher-request-promote":
      return "Pending request promoted";
    case "launcher-request-analysis-error":
      return "Analysis failed";
    case "launcher-request-analysis-launch":
      return "Queue worker launched";
    case "launcher-request-analysis-finish":
      return "Queue worker finished";
    case "launcher-request-analysis-launch-error":
      return "Queue worker launch error";
    case "launcher-request-analysis-requeue":
      return "Request requeued for review";
    default:
      return String(event.type || "Event");
  }
}

function formatEventDetail(event: RecentSaveEvent): string {
  const parts = [
    event.requestId ? `Request ${event.requestId}` : "",
    event.category ? `Category ${event.category}` : "",
    event.status ? `Status ${event.status}` : "",
    event.itemCount ? `${event.itemCount} item${event.itemCount === 1 ? "" : "s"}` : "",
    event.provider ? `Provider ${event.provider}` : "",
    event.model ? `Model ${event.model}` : "",
    event.reason ? `Reason ${event.reason}` : "",
    event.pid ? `PID ${event.pid}` : "",
    Number.isFinite(Number(event.code)) ? `Exit ${event.code}` : "",
    event.signal ? `Signal ${event.signal}` : "",
    event.error ? String(event.error) : "",
    event.textPreview ? `Preview: ${event.textPreview}` : "",
  ].filter(Boolean);
  return parts.join(" • ");
}

function openStudioPopup(worldId: string): boolean {
  const popup = openWorldshaperStudioWindow(worldId, window, { worldId });
  return Boolean(popup);
}

function openRepo(): void {
  window.location.assign("https://repo.andraxion.net/");
}

function openAdminPanelWindow(): boolean {
  const nextUrl = new URL(window.location.href);
  nextUrl.searchParams.set("admin", "requests");
  nextUrl.searchParams.set("tab", "requests");
  const popup = window.open(nextUrl.toString(), "worldshaper-admin-panel", "popup=yes,width=1620,height=980,resizable=yes,scrollbars=yes");
  if (popup) {
    popup.focus();
  }
  return Boolean(popup);
}

function WorldshaperLauncher() {
  const launcherWindowMode = readLauncherWindowMode();
  const adminWindowMode = launcherWindowMode === "admin";
  const [launchState, setLaunchState] = useState<LaunchState>("ready");
  const [error, setError] = useState("");
  const [worldId, setWorldId] = useState(DEFAULT_EDITOR_WORLD_ID_FALLBACK);
  const {
    adminPanelOpen,
    activeBoardTab,
    setActiveBoardTab,
    requests,
    requestsLoading,
    requestsError,
    requestDraftOpen,
    setRequestDraftOpen,
    requestDraft,
    setRequestDraft,
    requestSubmitting,
    requestMutatingId,
    requestSearchText,
    setRequestSearchText,
    requestFilterMenuOpen,
    setRequestFilterMenuOpen,
    requestStatusFilters,
    setRequestStatusFilters,
    requestTagFilters,
    setRequestTagFilters,
    expandedRequestIds,
    adminAccessGranted,
    adminPasswordDraft,
    setAdminPasswordDraft,
    adminAuthSubmitting,
    adminPasswordError,
    selectedAdminRequestId,
    selectedAdminAnalysisIndex,
    setSelectedAdminAnalysisIndex,
    adminSearchText,
    setAdminSearchText,
    adminFilterMenuOpen,
    setAdminFilterMenuOpen,
    adminStatusFilters,
    setAdminStatusFilters,
    adminTagFilters,
    setAdminTagFilters,
    adminEditorDraft,
    adminDetailTab,
    setAdminDetailTab,
    adminSaving,
    recentSaveEvents,
    logsLoading,
    logsModalOpen,
    setLogsModalOpen,
    logsError,
    queueTriggering,
    requeueingMode,
    adminNotice,
    refreshAdminData,
    loadRecentSaveEvents,
    handleAddRequest,
    handleAdminPanelToggle,
    handleAdminUnlock,
    handleSelectAdminRequest,
    updateAdminDraft,
    updateAdminDraftItem,
    handleSaveAdminRequest,
    handleApproveAdminRequest,
    handleRequeueAnalysis,
    handleToggleExpandedRequest,
    handleDeleteRequest,
    handleProcessPendingQueue,
    requestCount,
    pendingRequestCount,
    activeRequestCount,
    implementedRequestCount,
    queuedPendingRequestCount,
    needsReviewRequestCount,
    requestTagFilterOptions,
    requestStatusFilterOptions,
    filteredRequests,
    adminFilteredRequests,
    selectedAnalysisItem,
    standardizedTagOptions,
    categoryOptions,
    boardTitle,
    boardHint,
  } = useLauncherRequestBoard({ adminWindowMode });

  useEffect(() => {
    let cancelled = false;
    void resolveDefaultWorldId()
      .then((resolvedWorldId) => {
        if (cancelled) {
          return;
        }
        setWorldId(resolvedWorldId);
      })
      .catch(() => {
        if (cancelled) {
          return;
        }
        setWorldId(DEFAULT_EDITOR_WORLD_ID_FALLBACK);
      });

    return () => {
      cancelled = true;
    };
  }, []);

  async function handleLaunch(): Promise<void> {
    setError("");
    const nextWorldId = worldId || DEFAULT_EDITOR_WORLD_ID_FALLBACK;
    setLaunchState("opening");
    try {
      const resolvedWorldId = nextWorldId || await resolveDefaultWorldId().catch(() => DEFAULT_EDITOR_WORLD_ID_FALLBACK);
      setWorldId(resolvedWorldId);
      if (openStudioPopup(resolvedWorldId)) {
        setLaunchState("opened");
        return;
      }
      setLaunchState("blocked");
    } catch (nextError: unknown) {
      const nextErrorText = String(nextError || "Failed to prepare Worldshaper Studio.");
      setLaunchState("error");
      setError(nextErrorText);
    }
  }
  const isBusy = launchState === "opening";

  return (
    <main
      className={`launcher-shell ${adminWindowMode ? "launcher-shell-admin" : ""}`}
      style={{ "--launcher-background-image": `url(${launcherBackground})` } as CSSProperties}
    >
      <div className={`launcher-stack ${adminWindowMode ? "launcher-stack-admin" : ""}`}>
        {!adminWindowMode ? (
        <section className="launcher-hero-window" aria-labelledby="launcher-studio-title">
          <div className="launcher-hero-body">
            <div className="launcher-hero-stack">
              <div className="launcher-title-bubble">
                <h1 className="launcher-title" id="launcher-studio-title">Worldshaper Studio</h1>
              </div>
              <div className="launcher-actions launcher-actions-floating">
                <button type="button" className="launcher-primary-btn" onClick={() => void handleLaunch()} disabled={isBusy}>
                  Launch
                </button>
                <button type="button" className="launcher-secondary-btn" onClick={openRepo} disabled={isBusy}>
                  Open Repo
                </button>
              </div>
              {launchState === "blocked" ? <p className="launcher-error">Popup blocked. Allow popups, then press Launch again.</p> : null}
              {error ? <p className="launcher-error">{error}</p> : null}
            </div>
          </div>
        </section>
        ) : null}
        <section className="launcher-changelog-window" aria-labelledby="launcher-board-title">
          <div className="launcher-changelog-titlebar">
            <div className="launcher-changelog-title" id="launcher-board-title">{boardTitle}</div>
            <div className="launcher-changelog-hint">{boardHint}</div>
          </div>
          <div className="launcher-changelog-body">
            <div className="launcher-board-content">
              {!adminWindowMode ? (
              <div className="launcher-board-tabs">
                <button
                  type="button"
                  className={`launcher-secondary-btn launcher-board-tab ${activeBoardTab === "news" ? "is-active" : ""}`}
                  onClick={() => setActiveBoardTab("news")}
                >
                  News
                </button>
                <button
                  type="button"
                  className={`launcher-secondary-btn launcher-board-tab ${activeBoardTab === "requests" ? "is-active" : ""}`}
                  onClick={() => setActiveBoardTab("requests")}
                >
                  Requests
                </button>
              </div>
              ) : null}
              {activeBoardTab === "news" ? (
                <LauncherNewsPanel />
              ) : (
                adminPanelOpen ? (
                  <LauncherAdminPanel
                    adminAccessGranted={adminAccessGranted}
                    adminPasswordDraft={adminPasswordDraft}
                    setAdminPasswordDraft={setAdminPasswordDraft}
                    handleAdminUnlock={handleAdminUnlock}
                    adminAuthSubmitting={adminAuthSubmitting}
                    adminPasswordError={adminPasswordError}
                    handleProcessPendingQueue={handleProcessPendingQueue}
                    queueTriggering={queueTriggering}
                    refreshAdminData={refreshAdminData}
                    logsLoading={logsLoading}
                    setLogsModalOpen={setLogsModalOpen}
                    loadRecentSaveEvents={loadRecentSaveEvents}
                    queuedPendingRequestCount={queuedPendingRequestCount}
                    needsReviewRequestCount={needsReviewRequestCount}
                    pendingRequestCount={pendingRequestCount}
                    activeRequestCount={activeRequestCount}
                    implementedRequestCount={implementedRequestCount}
                    adminNotice={adminNotice}
                    logsError={logsError}
                    adminSearchText={adminSearchText}
                    setAdminSearchText={setAdminSearchText}
                    adminFilterMenuOpen={adminFilterMenuOpen}
                    setAdminFilterMenuOpen={setAdminFilterMenuOpen}
                    requestStatusFilterOptions={requestStatusFilterOptions}
                    adminStatusFilters={adminStatusFilters}
                    setAdminStatusFilters={setAdminStatusFilters}
                    requestTagFilterOptions={requestTagFilterOptions}
                    adminTagFilters={adminTagFilters}
                    setAdminTagFilters={setAdminTagFilters}
                    toggleStringSelection={toggleStringSelection}
                    requestsLoading={requestsLoading}
                    adminFilteredRequests={adminFilteredRequests}
                    requestMutatingId={requestMutatingId}
                    selectedAdminRequestId={selectedAdminRequestId}
                    handleSelectAdminRequest={handleSelectAdminRequest}
                    handleDeleteRequest={handleDeleteRequest}
                    adminEditorDraft={adminEditorDraft}
                    adminDetailTab={adminDetailTab}
                    setAdminDetailTab={setAdminDetailTab}
                    selectedAnalysisItem={selectedAnalysisItem}
                    selectedAdminAnalysisIndex={selectedAdminAnalysisIndex}
                    setSelectedAdminAnalysisIndex={setSelectedAdminAnalysisIndex}
                    updateAdminDraft={updateAdminDraft}
                    updateAdminDraftItem={updateAdminDraftItem}
                    standardizedTagOptions={standardizedTagOptions}
                    categoryOptions={categoryOptions}
                    handleSaveAdminRequest={handleSaveAdminRequest}
                    adminSaving={adminSaving}
                    requeueingMode={requeueingMode}
                    handleApproveAdminRequest={handleApproveAdminRequest}
                    handleRequeueAnalysis={handleRequeueAnalysis}
                  />
                ) : (
                  <LauncherPublicRequestBoard
                    requestCount={requestCount}
                    queuedPendingRequestCount={queuedPendingRequestCount}
                    needsReviewRequestCount={needsReviewRequestCount}
                    activeRequestCount={activeRequestCount}
                    implementedRequestCount={implementedRequestCount}
                    requestDraftOpen={requestDraftOpen}
                    requestSubmitting={requestSubmitting}
                    requestSearchText={requestSearchText}
                    requestFilterMenuOpen={requestFilterMenuOpen}
                    requestStatusFilterOptions={requestStatusFilterOptions}
                    requestTagFilterOptions={requestTagFilterOptions}
                    requestStatusFilters={requestStatusFilters}
                    requestTagFilters={requestTagFilters}
                    requestsLoading={requestsLoading}
                    requests={requests}
                    filteredRequests={filteredRequests}
                    expandedRequestIds={expandedRequestIds}
                    setRequestDraftOpen={setRequestDraftOpen}
                    handleAdminPanelToggle={handleAdminPanelToggle}
                    setRequestSearchText={setRequestSearchText}
                    setRequestFilterMenuOpen={setRequestFilterMenuOpen}
                    setRequestStatusFilters={setRequestStatusFilters}
                    setRequestTagFilters={setRequestTagFilters}
                    toggleStringSelection={toggleStringSelection}
                    handleToggleExpandedRequest={handleToggleExpandedRequest}
                    requestDraft={requestDraft}
                    setRequestDraft={setRequestDraft}
                    handleAddRequest={handleAddRequest}
                  />
                )
              )}
              {requestsError ? (
                <p className="launcher-request-error">{requestsError}</p>
              ) : null}
            </div>
          </div>
        </section>
        <div className="launcher-build-stamp">Build {__APP_BUILD__}</div>
      </div>
      {adminPanelOpen && logsModalOpen ? (
        <LauncherLogsModal
          logsLoading={logsLoading}
          recentSaveEvents={recentSaveEvents}
          setLogsModalOpen={setLogsModalOpen}
        />
      ) : null}
    </main>
  );
}

export default WorldshaperLauncher;
