// [nexus] Replacement onboarding wizard — 6-step full-page flow: hardware detection, mode selection, provider selection, voice, phone access, summary
// Exports `OnboardingWizard` to match the named import in App.tsx.
// Wired via Vite alias: all imports of ./components/OnboardingWizard are
// redirected here at build time; the original file is preserved for upstream rebase.

import { useState, useEffect } from "react";
import { useLocation, useNavigate, useParams } from "@/lib/router";
import { VOCAB } from "@paperclipai/branding";
import { useQueryClient } from "@tanstack/react-query";
import { useCompany } from "../context/CompanyContext";
import { useDialog } from "../context/DialogContext";
import { companiesApi } from "../api/companies";
import { agentsApi } from "../api/agents";
import { puterProxyApi } from "../api/puter-proxy";
import { queryKeys } from "../lib/queryKeys";
import { resolveRouteOnboardingOptions } from "../lib/onboarding-route";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { cn } from "../lib/utils";
import { ModeSelector } from "./onboarding/ModeSelector";
import { HardwareSummaryStep } from "./onboarding/HardwareSummaryStep";
import { ProviderSelectionStep } from "./onboarding/ProviderSelectionStep";
import { OnboardingSummaryStep } from "./onboarding/OnboardingSummaryStep";
import { VoiceStep } from "./onboarding/VoiceStep";
import { TelegramStep } from "./onboarding/TelegramStep";
import { useHardwareInfo } from "../hooks/useHardwareInfo";
import { updateNexusSettings, type NexusMode } from "../api/hardware";
import { useChatPanel } from "../context/ChatPanelContext";
import {
  Cpu,
  LayoutGrid,
  Cloud,
  Mic,
  Smartphone,
  CheckCircle,
  Check,
} from "lucide-react";
import type { LucideIcon } from "lucide-react";

const ADAPTER_LABELS: Record<string, string> = {
  claude_local: "Claude Code (detected)",
  hermes_local: "Hermes (detected)",
  openclaw_gateway: "OpenClaw Gateway (detected)",
};

function deriveProviderLabel(
  puterToken: string | null,
  googleOAuthStateId: string | null,
  apiKeyData: { provider: string; apiKey: string } | null,
  selectedAdapterChoice: string | null,
): string {
  if (selectedAdapterChoice) return ADAPTER_LABELS[selectedAdapterChoice] ?? selectedAdapterChoice;
  if (puterToken) return "Puter (free, zero-config)";
  if (googleOAuthStateId) return "Google Gemini (free tier)";
  if (apiKeyData) return `API key — ${apiKeyData.provider}`;
  return "None selected";
}

interface StepDef {
  id: number;
  name: string;
  icon: LucideIcon;
  title: string;
  description: string;
}

const STEPS: StepDef[] = [
  { id: 1, name: "Hardware", icon: Cpu, title: "Your hardware", description: "Detecting what your machine can do." },
  { id: 2, name: "Mode", icon: LayoutGrid, title: "Choose your mode", description: "How do you want to use Nexus?" },
  { id: 3, name: "Provider", icon: Cloud, title: "Choose a provider", description: "No API keys needed for the zero-config path." },
  { id: 4, name: "Voice", icon: Mic, title: "Voice features", description: "Speak to your assistant and hear responses read aloud. Runs entirely on your device." },
  { id: 5, name: "Phone Access", icon: Smartphone, title: "Phone Access", description: "Get notifications and send quick replies from your phone." },
  { id: 6, name: "Summary", icon: CheckCircle, title: "Ready to go", description: "Review your setup before starting." },
];

// [nexus] 6-step onboarding wizard: hardware detection -> mode selection -> provider selection -> voice -> phone access -> summary
export function OnboardingWizard() {
  const { onboardingOpen, onboardingOptions, closeOnboarding } = useDialog();
  const { companies, setSelectedCompanyId, loading: companiesLoading } = useCompany();
  const queryClient = useQueryClient();
  const navigate = useNavigate();
  const location = useLocation();
  const { companyPrefix } = useParams<{ companyPrefix?: string }>();
  const [routeDismissed, setRouteDismissed] = useState(false);
  const { setChatOpen } = useChatPanel();

  // Preserve wizard-show detection logic from the original OnboardingWizard
  const routeOnboardingOptions =
    companyPrefix && companiesLoading
      ? null
      : resolveRouteOnboardingOptions({
          pathname: location.pathname,
          companyPrefix,
          companies,
        });

  const effectiveOnboardingOpen =
    onboardingOpen || (routeOnboardingOptions !== null && !routeDismissed);

  useEffect(() => {
    setRouteDismissed(false);
  }, [location.pathname]);

  // Step state: 1 = hardware, 2 = mode, 3 = provider, 4 = voice, 5 = phone access, 6 = summary
  const [step, setStep] = useState(1);

  // Mode state: "both" pre-selected per UI-SPEC
  const [selectedMode, setSelectedMode] = useState<NexusMode>("both");

  // Voice preference — captured in step 4
  const [voiceEnabled, setVoiceEnabled] = useState(false);

  // [nexus] Provider credentials — captured in React state for post-company-creation submission
  const [puterToken, setPuterToken] = useState<string | null>(null);
  const [googleOAuthStateId, setGoogleOAuthStateId] = useState<string | null>(null);
  const [apiKeyData, setApiKeyData] = useState<{ provider: string; apiKey: string } | null>(null);
  const [selectedAdapterChoice, setSelectedAdapterChoice] = useState<string | null>(null);

  // Form state
  const [rootDir, setRootDir] = useState("");
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // [nexus] Hardware detection — only fetch when wizard is open
  const { data: hardwareInfo, isLoading: hwLoading, isError: hwError } = useHardwareInfo(effectiveOnboardingOpen);

  // [nexus] Adapter detection state — probe for adapters when wizard opens
  const [defaultAdapter, setDefaultAdapter] = useState<"claude_local" | "hermes_local">("claude_local");
  const [probing, setProbing] = useState(false);
  const [detectedAdapters, setDetectedAdapters] = useState<Record<string, boolean>>({});

  // Reset form when wizard closes
  useEffect(() => {
    if (!effectiveOnboardingOpen) {
      setRootDir("");
      setError(null);
      setLoading(false);
      setStep(1);
      setSelectedMode("both");
      setVoiceEnabled(false);
      setPuterToken(null);
      setGoogleOAuthStateId(null);
      setApiKeyData(null);
    }
  }, [effectiveOnboardingOpen]);

  // [nexus] Probe for adapter availability when wizard opens (parallel, fire-and-forget)
  useEffect(() => {
    if (!effectiveOnboardingOpen) return;
    setProbing(true);

    const probes = Promise.all([
      agentsApi.probeAdapter("hermes_local").catch(() => ({ available: false, status: "error" })),
      agentsApi.probeAdapter("claude_local").catch(() => ({ available: false, status: "error" })),
      agentsApi.probeAdapter("openclaw_gateway").catch(() => ({ available: false, status: "error" })),
    ]);

    probes.then(([hermes, claude, openclaw]) => {
      const detected: Record<string, boolean> = {
        hermes_local: hermes.available,
        claude_local: claude.available,
        openclaw_gateway: openclaw.available,
      };
      setDetectedAdapters(detected);
      if (hermes.available) setDefaultAdapter("hermes_local");
    }).catch(() => {}).finally(() => setProbing(false));
  }, [effectiveOnboardingOpen]);

  // [nexus] Shared workspace creation logic used by both handleSubmit and handleStartChat
  async function createWorkspace() {
    // Step 1: Create workspace (company) named after VOCAB.appName
    const company = await companiesApi.create({ name: VOCAB.appName });
    setSelectedCompanyId(company.id);
    queryClient.invalidateQueries({ queryKey: queryKeys.companies.all });

    // [nexus] hermes_local doesn't require a cwd; directory is optional
    const baseAdapterConfig = defaultAdapter === "hermes_local"
      ? (rootDir.trim() ? { cwd: rootDir.trim() } : {})
      : { cwd: rootDir.trim() };

    // [nexus] Hermes agents need a promptTemplate so they follow the Nexus heartbeat
    // workflow. The server's ensureDefaultInstructionsBundle will materialize this as
    // AGENTS.md alongside the full role bundle (HEARTBEAT.md, SOUL.md, TOOLS.md).
    const hermesPromptTemplate = [
      `You are "{{agentName}}", an AI agent managed by ${VOCAB.appName}.`,
      "",
      "Your identity:",
      "  Agent ID: {{agentId}}",
      "  Company ID: {{companyId}}",
      "  API Base: {{paperclipApiUrl}}",
      "  Run ID: {{runId}}",
      "",
      "IMPORTANT: Use the `terminal` tool with `curl` for ALL API calls.",
      'IMPORTANT: Always include `-H "X-Paperclip-Run-Id: {{runId}}"` on API calls that modify data.',
      "",
      "Before starting any task:",
      "1. Call `GET {{paperclipApiUrl}}/api/agents/me` to retrieve your managed instructions",
      "2. Follow the HEARTBEAT.md workflow from your instructions",
      "3. Use TOOLS.md for available API endpoints",
      "",
      "{{#taskId}}",
      "Assigned task: {{taskId}} - {{taskTitle}}",
      "{{/taskId}}",
    ].join("\n");

    const adapterConfig = defaultAdapter === "hermes_local"
      ? { ...baseAdapterConfig, promptTemplate: hermesPromptTemplate, persistSession: true }
      : baseAdapterConfig;

    const runtimeConfig = {
      heartbeat: {
        enabled: true,
        intervalSec: 3600,
        wakeOnDemand: true,
        cooldownSec: 10,
        maxConcurrentRuns: 1,
      },
    };

    // Step 2: Create PM agent with role "ceo" for elevated permissions
    await agentsApi.create(company.id, {
      name: "Project Manager",
      role: "ceo",
      adapterType: defaultAdapter,
      adapterConfig,
      runtimeConfig,
    });

    // Step 3: Create Engineer agent
    await agentsApi.create(company.id, {
      name: "Engineer",
      role: "engineer",
      adapterType: defaultAdapter,
      adapterConfig,
      runtimeConfig,
    });

    queryClient.invalidateQueries({
      queryKey: queryKeys.agents.list(company.id),
    });

    // Persist selected mode — non-blocking
    try {
      await updateNexusSettings({ mode: selectedMode });
    } catch {
      // Non-blocking — mode defaults to "both" if save fails
    }

    // Persist voice preference — non-blocking
    if (voiceEnabled) {
      try {
        await updateNexusSettings({ voiceEnabled: true });
      } catch {
        // Non-blocking
      }
    }

    // [nexus] Store collected provider credentials after company creation — all non-blocking
    if (puterToken) {
      await puterProxyApi.storeToken(company.id, puterToken).catch(() => {});
    }
    if (googleOAuthStateId) {
      // Claim Google OAuth tokens for this company
      await puterProxyApi.claimGoogleTokens(googleOAuthStateId, company.id).catch(() => {});
    }
    if (apiKeyData) {
      await puterProxyApi.storeApiKey(company.id, apiKeyData.provider, apiKeyData.apiKey).catch(() => {});
    }

    return company;
  }

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    if (defaultAdapter === "claude_local" && !rootDir.trim()) return;

    setLoading(true);
    setError(null);

    try {
      const company = await createWorkspace();

      // [nexus] Mode-aware landing: personal_ai and "both" land on the
      // Assistant (the Nexus-first experience); project_builder lands on
      // the classic dashboard. Matches Sidebar.tsx and App.tsx
      // CompanyRootRedirect — the user should never touch the Paperclip
      // dashboard unless they explicitly chose project_builder mode.
      const landingPath = selectedMode === "project_builder" ? "dashboard" : "assistant";
      closeOnboarding();
      navigate(`/${company.issuePrefix}/${landingPath}`);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Setup failed. Please try again.");
      setLoading(false);
    }
  }

  // [nexus] ONBD-06: Creates workspace then opens chat panel after navigation
  async function handleStartChat() {
    // Guard: claude_local requires rootDir
    if (defaultAdapter === "claude_local" && !rootDir.trim()) {
      setError("Root directory is required for Claude Code. Go back to step 5 to set it.");
      return;
    }

    setLoading(true);
    setError(null);

    try {
      const company = await createWorkspace();

      // [nexus] Mode-aware landing + chat panel open — same logic as
      // handleSubmit but with the chat drawer toggled on.
      const landingPath = selectedMode === "project_builder" ? "dashboard" : "assistant";
      closeOnboarding();
      navigate(`/${company.issuePrefix}/${landingPath}`);
      setChatOpen(true);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Setup failed. Please try again.");
      setLoading(false);
    }
  }

  // Current step definition
  const currentStep = STEPS.find(s => s.id === step) ?? STEPS[0];

  // Navigation helpers
  function goBack() {
    if (step > 1) setStep(step - 1);
  }

  function goNext() {
    if (step < 6) setStep(step + 1);
  }

  // Render step content
  function renderStepContent() {
    switch (step) {
      case 1:
        return (
          <HardwareSummaryStep
            hardwareInfo={hardwareInfo}
            isLoading={hwLoading}
            isError={hwError}
          />
        );
      case 2:
        return <ModeSelector value={selectedMode} onChange={setSelectedMode} />;
      case 3:
        return (
          <ProviderSelectionStep
            onPuterToken={(token) => { setPuterToken(token); setSelectedAdapterChoice(null); }}
            onGoogleOAuthState={(id) => { setGoogleOAuthStateId(id); setSelectedAdapterChoice(null); }}
            onApiKey={(provider, apiKey) => { setApiKeyData({ provider, apiKey }); setSelectedAdapterChoice(null); }}
            onAdapterSelected={(adapter) => { setSelectedAdapterChoice(adapter); setPuterToken(null); setGoogleOAuthStateId(null); setApiKeyData(null); }}
            onSkip={goNext}
            onContinue={goNext}
            detectedAdapters={detectedAdapters}
            probing={probing}
          />
        );
      case 4:
        return (
          <VoiceStep
            onEnable={() => {
              setVoiceEnabled(true);
              goNext();
            }}
            onSkip={goNext}
            voiceCapability={hardwareInfo?.voiceCapability}
          />
        );
      case 5:
        return (
          <TelegramStep
            onNext={goNext}
            onBack={goBack}
          />
        );
      case 6:
        return (
          <OnboardingSummaryStep
            hardwareInfo={hardwareInfo}
            selectedMode={selectedMode}
            providerLabel={deriveProviderLabel(puterToken, googleOAuthStateId, apiKeyData, selectedAdapterChoice)}
            rootDir={rootDir}
            onRootDirChange={setRootDir}
            loading={loading}
            error={error}
            onStartChat={handleStartChat}
            onBack={goBack}
            voiceEnabled={voiceEnabled}
            defaultAdapter={defaultAdapter}
          />
        );
      default:
        return null;
    }
  }

  // Steps 3, 4, 5 have their own navigation — don't render the shared footer
  const stepHasOwnNav = step === 3 || step === 4 || step === 5 || step === 6;

  if (!effectiveOnboardingOpen) return null;

  return (
    <div className="fixed inset-0 z-50 flex bg-background">
      {/* Left sidebar - step navigation (hidden on mobile) */}
      <aside className="hidden md:flex w-[260px] flex-col border-r border-border bg-card p-6">
        {/* Logo/title at top */}
        <div className="mb-8">
          <h1 className="text-lg font-bold">Nexus Setup</h1>
          <p className="text-xs text-muted-foreground mt-1">Configure your workspace</p>
        </div>

        {/* Step list */}
        <nav className="flex flex-col gap-1">
          {STEPS.map((s) => {
            const isCompleted = s.id < step;
            const isCurrent = s.id === step;
            const isUpcoming = s.id > step;
            const Icon = s.icon;

            return (
              <button
                key={s.id}
                type="button"
                onClick={() => {
                  if (isCompleted) setStep(s.id);
                }}
                disabled={isUpcoming}
                className={cn(
                  "flex items-center gap-3 px-3 py-2.5 text-sm rounded-lg transition-colors text-left",
                  isCurrent && "bg-primary/10 text-primary font-medium",
                  isCompleted && "text-foreground hover:bg-muted/50 cursor-pointer",
                  isUpcoming && "text-muted-foreground/50 cursor-default"
                )}
              >
                {isCompleted ? (
                  <Check className="h-4 w-4 shrink-0 text-[color:var(--chart-2)]" />
                ) : (
                  <Icon className={cn(
                    "h-4 w-4 shrink-0",
                    isCurrent ? "text-primary" : "text-muted-foreground/50"
                  )} />
                )}
                <span>{s.name}</span>
              </button>
            );
          })}
        </nav>
      </aside>

      {/* Mobile step indicator - horizontal bar at top */}
      <div className="md:hidden fixed top-0 left-0 right-0 z-50 bg-card border-b border-border px-4 py-3">
        <div className="flex items-center justify-between mb-2">
          <span className="text-sm font-medium">Nexus Setup</span>
          <span className="text-xs text-muted-foreground">Step {step} of 6</span>
        </div>
        <div className="flex gap-1.5">
          {STEPS.map((s) => (
            <div
              key={s.id}
              className={cn(
                "h-1 flex-1 rounded-full transition-colors",
                s.id < step && "bg-[color:var(--chart-2)]",
                s.id === step && "bg-primary",
                s.id > step && "bg-muted"
              )}
            />
          ))}
        </div>
      </div>

      {/* Right content area */}
      <main className="flex-1 flex flex-col overflow-y-auto">
        <div className="flex-1 flex items-start justify-center p-8 md:p-12 pt-20 md:pt-12">
          <div className="w-full max-w-[640px]">
            {/* Step heading */}
            <h2 className="text-2xl md:text-3xl font-bold mb-2">{currentStep.title}</h2>
            <p className="text-base text-muted-foreground mb-8">{currentStep.description}</p>

            {/* Step content */}
            {renderStepContent()}

            {/* Shared navigation footer — only for steps 1 and 2 */}
            {!stepHasOwnNav && (
              <div className="flex items-center justify-between mt-8 pt-6 border-t border-border">
                {step > 1 ? (
                  <Button variant="ghost" size="sm" onClick={goBack}>Back</Button>
                ) : (
                  <div />
                )}
                <Button className="ml-auto" onClick={goNext}>Continue</Button>
              </div>
            )}
          </div>
        </div>
      </main>
    </div>
  );
}
