import { useEffect, useState, useRef } from 'react'
import { useParams, useNavigate, useLocation } from 'react-router-dom'
import { ChevronLeft, ChevronRight, ListOrdered, Settings2, X, Plus, Check, AlertCircle } from 'lucide-react'
import { treesApi } from '@/api/trees'
import { sessionsApi } from '@/api/sessions'
import { stepsApi } from '@/api/steps'
import type { Tree, Session, ProceduralStep, DecisionRecord, RuntimeStep, CustomProceduralStep, IntakeFormField } from '@/types'
import type { CustomStep } from '@/types/session'
import type { Step } from '@/types/step'
import { StepChecklist } from '@/components/procedural/StepChecklist'
import { StepDetail } from '@/components/procedural/StepDetail'
import { ProgressBar } from '@/components/procedural/ProgressBar'
import { CompletionSummary } from '@/components/procedural/CompletionSummary'
import { ConfirmDialog } from '@/components/common/ConfirmDialog'
import { Spinner } from '@/components/common/Spinner'
import { cn } from '@/lib/utils'
import { toast } from '@/lib/toast'
import { StepFeedback } from '@/components/session/StepFeedback'
import { CSATModal } from '@/components/session/CSATModal'
import { hasBeenRated } from '@/components/session/csatUtils'
import { MaintenanceContextStrip } from '@/components/maintenance/MaintenanceContextStrip'
import { CustomStepModal } from '@/components/step-library/CustomStepModal'
import type { CustomStepDraft } from '@/components/step-library/CustomStepModal'
import { PostStepActionModal } from '@/components/session/PostStepActionModal'
import { CopilotPanel } from '@/components/copilot/CopilotPanel'
import { CopilotToggle } from '@/components/copilot/CopilotToggle'
import { integrationsApi, sessionPsaApi } from '@/api/integrations'
import { TicketPickerModal } from '@/components/session/TicketPickerModal'
import { TicketLinkIndicator } from '@/components/session/TicketLinkIndicator'
import type { PSATicketInfo } from '@/types/integrations'

interface StepState {
  notes: string
  verificationValue: string
  completedAt: string | null
}

function buildRuntimeSteps(baseSteps: ProceduralStep[], customSteps: CustomStep[]): RuntimeStep[] {
  const result: RuntimeStep[] = [...baseSteps]
  const sorted = [...customSteps].sort((a, b) => a.timestamp.localeCompare(b.timestamp))
  for (const cs of sorted) {
    const afterIdx = result.findIndex((s) => s.id === cs.inserted_after_node_id)
    const insertAt = afterIdx >= 0 ? afterIdx + 1 : result.length
    const runtimeCustom: CustomProceduralStep = {
      id: cs.id,
      type: 'procedure_step',
      title: cs.step_data.title,
      description: cs.step_data.content?.instructions,
      content_type: 'action',
      commands: cs.step_data.content?.commands?.map((c) => ({
        code: c.command,
        label: c.label,
      })),
      isCustom: true,
    }
    result.splice(insertAt, 0, runtimeCustom)
  }
  return result
}

export function ProceduralNavigationPage() {
  const { id: treeId } = useParams<{ id: string }>()
  const navigate = useNavigate()
  const location = useLocation()
  const locationState = location.state as { sessionId?: string } | undefined

  const [tree, setTree] = useState<Tree | null>(null)
  const [session, setSession] = useState<Session | null>(null)
  const [isLoading, setIsLoading] = useState(true)
  const [sessionVariables, setSessionVariables] = useState<Record<string, string>>({})
  const [currentStepIndex, setCurrentStepIndex] = useState(0)
  const [stepStates, setStepStates] = useState<Map<string, StepState>>(new Map())
  const [isComplete, setIsComplete] = useState(false)
  const [completedAt, setCompletedAt] = useState<string>('')
  const [showExitConfirm, setShowExitConfirm] = useState(false)
  const [sidebarOpen, setSidebarOpen] = useState(true)
  const [paramsOpen, setParamsOpen] = useState(false)
  const [showCsatModal, setShowCsatModal] = useState(false)
  const [elapsedMinutes, setElapsedMinutes] = useState(0)
  const [batchProgress, setBatchProgress] = useState<{ completed: number; total: number } | null>(null)
  const timerRef = useRef<ReturnType<typeof setInterval> | null>(null)

  // Custom step state
  const [runtimeSteps, setRuntimeSteps] = useState<RuntimeStep[]>([])
  const [sessionCustomSteps, setSessionCustomSteps] = useState<CustomStep[]>([])
  const [showCustomStepModal, setShowCustomStepModal] = useState(false)
  const [showPostStepModal, setShowPostStepModal] = useState(false)
  const [pendingCustomStep, setPendingCustomStep] = useState<Step | CustomStepDraft | null>(null)
  const [pendingIsFromLibrary, setPendingIsFromLibrary] = useState(false)
  const [isSavingStep, setIsSavingStep] = useState(false)
  const [copilotOpen, setCopilotOpen] = useState(false)

  // PSA ticket link state
  const [hasConnection, setHasConnection] = useState(false)
  const [showTicketPicker, setShowTicketPicker] = useState(false)
  const [psaTicketInfo, setPsaTicketInfo] = useState<PSATicketInfo | null>(null)

  // Editable variables panel state
  const [editingVarName, setEditingVarName] = useState<string | null>(null)
  const [editingVarValue, setEditingVarValue] = useState('')
  const [showUnfilledWarning, setShowUnfilledWarning] = useState(false)

  // Get intake form fields from tree snapshot or tree
  const intakeFields: IntakeFormField[] = (() => {
    if (tree?.intake_form && tree.intake_form.length > 0) return tree.intake_form
    // Fallback: check tree snapshot on session
    const snapshot = session?.tree_snapshot as Record<string, unknown> | undefined
    if (snapshot?.intake_form && Array.isArray(snapshot.intake_form)) {
      return snapshot.intake_form as IntakeFormField[]
    }
    return []
  })()

  // Get procedural steps from tree
  const getSteps = (): ProceduralStep[] => {
    if (!tree) return []
    const structure = tree.tree_structure as unknown as { steps?: ProceduralStep[] }
    return structure.steps || []
  }

  const steps = getSteps()
  const procedureSteps = runtimeSteps.filter((s) => s.type === 'procedure_step')
  const completedStepIds = new Set(
    Array.from(stepStates.entries())
      .filter(([, state]) => state.completedAt)
      .map(([id]) => id)
  )

  const estimatedTotalMinutes = procedureSteps.reduce(
    (sum, step) => sum + (('estimated_minutes' in step ? step.estimated_minutes : undefined) || 0),
    0
  )

  // Load tree
  useEffect(() => {
    if (!treeId) return
    loadTree(treeId)
    return () => {
      if (timerRef.current) clearInterval(timerRef.current)
    }
  }, [treeId])

  // Check for PSA connection on mount
  useEffect(() => {
    integrationsApi.getConnection()
      .then((conn) => setHasConnection(!!conn))
      .catch(() => setHasConnection(false))
  }, [])

  const handleTicketLinked = (linkedTicketId: string, ticket: PSATicketInfo) => {
    setPsaTicketInfo(ticket)
    setSession((prev) => prev ? { ...prev, psa_ticket_id: linkedTicketId } : prev)
    setShowTicketPicker(false)
    toast.success(`Linked to CW #${linkedTicketId}`)
  }

  const handleTicketUnlink = async () => {
    if (!session) return
    try {
      await sessionPsaApi.linkTicket(session.id, null)
      setSession((prev) => prev ? { ...prev, psa_ticket_id: null } : prev)
      setPsaTicketInfo(null)
      toast.success('Ticket unlinked')
    } catch {
      toast.error('Failed to unlink ticket')
    }
  }

  // Parse backend timestamp — ensure UTC if no timezone info
  const parseTimestamp = (ts: string) => {
    if (!ts.endsWith('Z') && !ts.includes('+') && !/\d{2}:\d{2}$/.test(ts.slice(-5))) {
      return new Date(ts + 'Z')
    }
    return new Date(ts)
  }

  // Elapsed time timer
  useEffect(() => {
    if (session && session.started_at && !isComplete) {
      const calcElapsed = () => {
        const start = parseTimestamp(session.started_at!).getTime()
        setElapsedMinutes(Math.max(0, Math.floor((Date.now() - start) / 60000)))
      }
      calcElapsed()
      timerRef.current = setInterval(calcElapsed, 30000)
    }
    return () => {
      if (timerRef.current) clearInterval(timerRef.current)
    }
  }, [session, isComplete])

  // Fetch batch progress once when session loads (maintenance flows only)
  useEffect(() => {
    if (!session?.batch_id) return
    sessionsApi.list({ batch_id: session.batch_id, size: 100 })
      .then(data => {
        if (Array.isArray(data) && data.length > 0) {
          const completed = data.filter(s => s.completed_at).length
          setBatchProgress({ completed, total: data.length })
        }
      })
      .catch(() => {})
  }, [session?.batch_id])

  const loadTree = async (id: string) => {
    setIsLoading(true)
    try {
      const treeData = await treesApi.get(id)
      if (treeData.tree_type !== 'procedural' && treeData.tree_type !== 'maintenance') {
        navigate(`/trees/${id}/navigate`, { replace: true })
        return
      }
      setTree(treeData)

      // If resuming an existing session
      if (locationState?.sessionId) {
        await resumeSession(treeData, locationState.sessionId)
        return
      }

      // Start session immediately — no intake form modal
      // Variables will be filled inline during execution
      await startSession(id, {}, treeData)
    } catch {
      toast.error('Failed to load flow')
      navigate('/trees')
    } finally {
      setIsLoading(false)
    }
  }

  const startSession = async (id: string, variables: Record<string, string>, treeData?: Tree) => {
    try {
      const newSession = await sessionsApi.create({
        tree_id: id,
        session_variables: Object.keys(variables).length > 0 ? variables : undefined,
      })
      setSession(newSession)
      setSessionVariables(variables)

      // Initialize step states — use passed treeData since `tree` state may not have committed yet
      const initialStates = new Map<string, StepState>()
      const allSteps = getStepsFromTree(treeData || tree!)
      for (const step of allSteps) {
        initialStates.set(step.id, { notes: '', verificationValue: '', completedAt: null })
      }
      setStepStates(initialStates)
      setRuntimeSteps(allSteps)
      setSessionCustomSteps([])
    } catch {
      toast.error('Failed to start session')
    }
  }

  const resumeSession = async (treeData: Tree, sessionId: string) => {
    try {
      const sessionData = await sessionsApi.get(sessionId)
      setSession(sessionData)
      setSessionVariables(sessionData.session_variables || {})

      // Initialize step states from session decisions
      const allSteps = getStepsFromTree(treeData)

      // Initialize custom steps from session data
      const customSteps = sessionData.custom_steps || []
      setSessionCustomSteps(customSteps)
      const hydrated = buildRuntimeSteps(allSteps, customSteps)
      setRuntimeSteps(hydrated)

      const initialStates = new Map<string, StepState>()
      for (const step of hydrated) {
        if (step.type === 'procedure_step') {
          initialStates.set(step.id, { notes: '', verificationValue: '', completedAt: null })
        }
      }

      // Hydrate completed steps from decisions
      for (const decision of sessionData.decisions || []) {
        if (decision.answer === 'completed' && initialStates.has(decision.node_id)) {
          initialStates.set(decision.node_id, {
            notes: decision.notes || '',
            verificationValue: decision.command_output || '',
            completedAt: decision.exited_at || decision.timestamp,
          })
        }
      }
      setStepStates(initialStates)

      // Set current step to first incomplete step
      const pSteps = hydrated.filter((s) => s.type === 'procedure_step')
      const firstIncomplete = pSteps.findIndex((s) => !initialStates.get(s.id)?.completedAt)
      setCurrentStepIndex(firstIncomplete >= 0 ? firstIncomplete : pSteps.length - 1)
    } catch {
      toast.error('Failed to resume session')
      navigate('/trees')
    }
  }

  const getStepsFromTree = (t: Tree): ProceduralStep[] => {
    const structure = t.tree_structure as unknown as { steps?: ProceduralStep[] }
    return structure.steps || []
  }

  // Handle inline variable submission (from StepDetail or variables panel)
  const handleVariableSubmit = async (variableName: string, value: string) => {
    if (!session) return

    // Optimistic update
    const newVars = { ...sessionVariables, [variableName]: value }
    setSessionVariables(newVars)

    try {
      await sessionsApi.updateVariables(session.id, { [variableName]: value })
    } catch {
      // Revert on failure
      setSessionVariables(sessionVariables)
      toast.error('Failed to save variable')
    }
  }

  const handleMarkComplete = async () => {
    if (!session || procedureSteps.length === 0) return

    const currentStep = procedureSteps[currentStepIndex]
    if (!currentStep) return

    const now = new Date().toISOString()

    // Update step state
    setStepStates((prev) => {
      const next = new Map(prev)
      const existing = next.get(currentStep.id) || { notes: '', verificationValue: '', completedAt: null }
      next.set(currentStep.id, { ...existing, completedAt: now })
      return next
    })

    // Create a decision record for this step
    const stepState = stepStates.get(currentStep.id)
    const decision: DecisionRecord = {
      node_id: currentStep.id,
      question: currentStep.title,
      answer: 'completed',
      action_performed: currentStep.description || null,
      notes: stepState?.notes || null,
      command_output: stepState?.verificationValue || null,
      automation_used: false,
      timestamp: now,
      entered_at: null,
      exited_at: now,
      duration_seconds: null,
      attachments: [],
    }

    try {
      const updatedDecisions = [...(session.decisions || []), decision]
      await sessionsApi.update(session.id, {
        decisions: updatedDecisions,
        path_taken: [...(session.path_taken || []), currentStep.id],
      })

      setSession((prev) => prev ? {
        ...prev,
        decisions: updatedDecisions,
        path_taken: [...(prev.path_taken || []), currentStep.id],
      } : prev)

      // Move to next step or complete
      if (currentStepIndex >= procedureSteps.length - 1) {
        // Last step — check for unfilled required variables
        const unfilledReqVars = intakeFields.filter(
          f => f.required && !sessionVariables[f.variable_name]?.trim()
        )
        if (unfilledReqVars.length > 0 && !showUnfilledWarning) {
          // Show warning but don't block
          setShowUnfilledWarning(true)
          return
        }
        setShowUnfilledWarning(false)

        // Complete the procedure
        const completedTime = new Date().toISOString()
        await sessionsApi.complete(session.id, {
          outcome: 'resolved',
          outcome_notes: `Procedure completed. ${procedureSteps.length} steps finished.`,
        })
        setCompletedAt(completedTime)
        setIsComplete(true)
        if (!hasBeenRated(session.id)) {
          setShowCsatModal(true)
        }
      } else {
        setCurrentStepIndex(currentStepIndex + 1)
      }
    } catch {
      toast.error('Failed to save progress')
    }
  }

  const handleStepNotesChange = (notes: string) => {
    const currentStep = procedureSteps[currentStepIndex]
    if (!currentStep) return
    setStepStates((prev) => {
      const next = new Map(prev)
      const existing = next.get(currentStep.id) || { notes: '', verificationValue: '', completedAt: null }
      next.set(currentStep.id, { ...existing, notes })
      return next
    })
  }

  const handleVerificationChange = (value: string) => {
    const currentStep = procedureSteps[currentStepIndex]
    if (!currentStep) return
    setStepStates((prev) => {
      const next = new Map(prev)
      const existing = next.get(currentStep.id) || { notes: '', verificationValue: '', completedAt: null }
      next.set(currentStep.id, { ...existing, verificationValue: value })
      return next
    })
  }

  const handleCsatClose = () => {
    setShowCsatModal(false)
  }

  const handleStepCreated = (step: Step | CustomStepDraft, isFromLibrary: boolean) => {
    setPendingCustomStep(step)
    setPendingIsFromLibrary(isFromLibrary)
    setShowCustomStepModal(false)
    setShowPostStepModal(true)
  }

  const handleInsertCustomStep = async (step: Step | CustomStepDraft) => {
    if (!session) return

    const id = crypto.randomUUID()
    const currentStep = procedureSteps[currentStepIndex]
    const insertedAfterId = currentStep?.id ?? ''

    const runtimeCustom: CustomProceduralStep = {
      id,
      type: 'procedure_step',
      title: step.title,
      description: step.content?.instructions,
      content_type: 'action',
      commands: step.content?.commands?.map((c) => ({
        code: c.command,
        label: c.label,
      })),
      isCustom: true,
    }

    setRuntimeSteps((prev) => {
      const next = [...prev]
      const globalIdx = next.findIndex((s) => s.id === insertedAfterId)
      const insertAt = globalIdx >= 0 ? globalIdx + 1 : next.length
      next.splice(insertAt, 0, runtimeCustom)
      return next
    })

    setStepStates((prev) => {
      const next = new Map(prev)
      next.set(id, { notes: '', verificationValue: '', completedAt: null })
      return next
    })

    const newCustomStep: CustomStep = {
      id,
      inserted_after_node_id: insertedAfterId,
      step_data: step,
      timestamp: new Date().toISOString(),
    }
    const newCustomSteps = [...sessionCustomSteps, newCustomStep]
    setSessionCustomSteps(newCustomSteps)

    try {
      await sessionsApi.update(session.id, { custom_steps: newCustomSteps })
    } catch {
      toast.error('Failed to save custom step')
    }

    setCurrentStepIndex(prev => prev + 1)
  }

  const handleSaveForLater = async () => {
    if (!pendingCustomStep || pendingIsFromLibrary) return
    setIsSavingStep(true)
    try {
      await stepsApi.create({
        title: pendingCustomStep.title,
        step_type: pendingCustomStep.step_type,
        content: pendingCustomStep.content,
        visibility: 'private',
      })
      toast.success('Step saved to library')
    } catch {
      toast.error('Failed to save step')
    } finally {
      setIsSavingStep(false)
      setShowPostStepModal(false)
      setPendingCustomStep(null)
    }
  }

  const handleUseNow = async () => {
    if (!pendingCustomStep) return
    setShowPostStepModal(false)
    await handleInsertCustomStep(pendingCustomStep)
    setPendingCustomStep(null)
  }

  const handleBoth = async () => {
    if (!pendingCustomStep || pendingIsFromLibrary) return
    setIsSavingStep(true)
    try {
      await stepsApi.create({
        title: pendingCustomStep.title,
        step_type: pendingCustomStep.step_type,
        content: pendingCustomStep.content,
        visibility: 'private',
      })
    } catch {
      toast.error('Failed to save step to library')
    } finally {
      setIsSavingStep(false)
    }
    setShowPostStepModal(false)
    await handleInsertCustomStep(pendingCustomStep)
    setPendingCustomStep(null)
  }

  // Variables panel: start editing
  const startEditingVar = (varName: string) => {
    setEditingVarName(varName)
    setEditingVarValue(sessionVariables[varName] || '')
  }

  // Variables panel: save edit
  const saveEditingVar = () => {
    if (editingVarName && editingVarValue.trim()) {
      handleVariableSubmit(editingVarName, editingVarValue.trim())
    }
    setEditingVarName(null)
    setEditingVarValue('')
  }

  // Loading state
  if (isLoading) {
    return (
      <div className="flex min-h-[50vh] items-center justify-center">
        <Spinner />
      </div>
    )
  }

  // Completion summary
  if (isComplete && tree && session) {
    return (
      <div className="container mx-auto px-4 py-8 sm:px-6">
        <CompletionSummary
          treeName={tree.name}
          steps={steps}
          completions={new Map(
            Array.from(stepStates.entries())
              .filter(([, s]) => s.completedAt)
              .map(([id, s]) => [id, {
                stepId: id,
                notes: s.notes,
                verificationValue: s.verificationValue,
                completedAt: s.completedAt!,
              }])
          )}
          variables={sessionVariables}
          startedAt={session.started_at || ''}
          completedAt={completedAt}
          onExport={() => navigate(`/sessions/${session.id}`)}
          onClose={() => navigate('/trees')}
        />
      </div>
    )
  }

  // No session yet
  if (!session || !tree) return null

  const currentStep = procedureSteps[currentStepIndex]
  const currentStepState = currentStep ? stepStates.get(currentStep.id) : undefined

  // Count unfilled required variables
  const unfilledRequired = intakeFields.filter(
    f => f.required && !sessionVariables[f.variable_name]?.trim()
  ).length

  return (
    <div className="flex h-full min-h-0 flex-col overflow-hidden">
      {/* Top bar */}
      <div className="border-b border-border px-4 py-3 sm:px-6">
        <div className="flex items-center justify-between gap-4">
          <div className="flex items-center gap-3">
            <button
              onClick={() => setSidebarOpen(!sidebarOpen)}
              className="rounded-md p-1.5 text-muted-foreground hover:bg-accent hover:text-foreground lg:hidden"
            >
              {sidebarOpen ? <ChevronLeft className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
            </button>
            <ListOrdered className="h-5 w-5 text-muted-foreground" />
            <h1 className="text-sm font-semibold text-foreground sm:text-base">{tree.name}</h1>
          </div>
          <button
            onClick={() => {
              if (currentStepIndex > 0) {
                setShowExitConfirm(true)
              } else {
                navigate('/trees')
              }
            }}
            className="rounded-md border border-border px-3 py-1.5 text-xs font-medium text-muted-foreground hover:bg-accent hover:text-foreground transition-colors"
          >
            <X className="mr-1 inline h-3.5 w-3.5" />
            Exit
          </button>
        </div>
        {session && (
          <div className="mt-1.5">
            <TicketLinkIndicator
              session={session}
              hasConnection={hasConnection}
              onLinkClick={() => setShowTicketPicker(true)}
              onUnlink={handleTicketUnlink}
              ticketInfo={psaTicketInfo}
            />
          </div>
        )}
        <div className="mt-2">
          <ProgressBar
            currentStep={completedStepIds.size}
            totalSteps={procedureSteps.length}
            elapsedMinutes={elapsedMinutes}
            estimatedTotalMinutes={estimatedTotalMinutes || undefined}
          />
        </div>
      </div>

      {/* Maintenance context strip */}
      {tree?.tree_type === 'maintenance' && session && (
        <MaintenanceContextStrip
          treeId={treeId!}
          targetLabel={session.target_label}
          batchId={session.batch_id}
          batchProgress={batchProgress}
        />
      )}

      {/* Main content */}
      <div className="flex min-h-0 flex-1 overflow-hidden">
        {/* Left sidebar - step checklist */}
        <div
          className={cn(
            'min-h-0 border-r border-border bg-card transition-all duration-200',
            sidebarOpen ? 'w-72 overflow-y-auto p-3' : 'w-0 overflow-hidden p-0'
          )}
        >
          {sidebarOpen && (
            <>
              <StepChecklist
                steps={runtimeSteps}
                currentStepIndex={currentStepIndex}
                completedStepIds={completedStepIds}
                onStepClick={setCurrentStepIndex}
              />

              {/* Session Variables button */}
              {intakeFields.length > 0 && (
                <div className="mt-3 border-t border-border pt-3">
                  <button
                    onClick={() => setParamsOpen(true)}
                    className="flex w-full items-center gap-2 rounded-lg border border-border px-3 py-2 text-xs text-muted-foreground hover:bg-accent hover:text-muted-foreground"
                  >
                    <Settings2 className="h-3.5 w-3.5" />
                    Session Variables
                    {unfilledRequired > 0 && (
                      <span className="ml-auto flex h-4 w-4 items-center justify-center rounded-full bg-amber-400/20 text-[0.6rem] font-bold text-amber-400">
                        {unfilledRequired}
                      </span>
                    )}
                  </button>
                </div>
              )}
            </>
          )}
        </div>

        {/* Right panel - step detail + copilot */}
        <div className="min-h-0 flex-1 overflow-y-auto overscroll-y-contain p-4 sm:p-6">
          {currentStep && (
            <StepDetail
              step={currentStep}
              stepNumber={currentStepIndex + 1}
              totalSteps={procedureSteps.length}
              variables={sessionVariables}
              notes={currentStepState?.notes || ''}
              onNotesChange={handleStepNotesChange}
              verificationValue={currentStepState?.verificationValue || ''}
              onVerificationChange={handleVerificationChange}
              isCompleted={completedStepIds.has(currentStep.id)}
              onMarkComplete={handleMarkComplete}
              isLast={currentStepIndex === procedureSteps.length - 1}
              intakeFields={intakeFields}
              onVariableSubmit={handleVariableSubmit}
            />
          )}

          {/* Add custom step — only on current active incomplete non-custom step */}
          {currentStep && !completedStepIds.has(currentStep.id) && !('isCustom' in currentStep && currentStep.isCustom) && (
            <div className="mt-4">
              <button
                onClick={() => setShowCustomStepModal(true)}
                className="flex w-full items-center justify-center gap-2 rounded-lg border border-dashed border-border px-4 py-2.5 text-sm text-muted-foreground transition-colors hover:border-primary/50 hover:text-foreground"
              >
                <Plus className="h-4 w-4" />
                Add Step
              </button>
            </div>
          )}

          {session && currentStep && !('isCustom' in currentStep && currentStep.isCustom) && (
            <div className="mt-3 flex justify-end">
              <StepFeedback stepId={currentStep.id} sessionId={session.id} />
            </div>
          )}
        </div>

        {/* AI Copilot - in-flow panel */}
        {treeId && copilotOpen && (
          <CopilotPanel
            isOpen={copilotOpen}
            onClose={() => setCopilotOpen(false)}
            treeId={treeId}
            sessionId={session?.id}
            currentNodeId={runtimeSteps[currentStepIndex]?.id}
          />
        )}
      </div>

      {/* CSAT Modal */}
      {session && (
        <CSATModal
          isOpen={showCsatModal}
          onClose={handleCsatClose}
          sessionId={session.id}
        />
      )}

      <ConfirmDialog
        isOpen={showExitConfirm}
        onClose={() => setShowExitConfirm(false)}
        onConfirm={() => navigate('/trees')}
        title="Exit Session"
        message="You have progress in this session. Are you sure you want to exit? Your progress will not be saved."
        confirmLabel="Exit"
      />

      <ConfirmDialog
        isOpen={showUnfilledWarning}
        onClose={() => setShowUnfilledWarning(false)}
        onConfirm={handleMarkComplete}
        title="Unfilled Variables"
        message={`${intakeFields.filter(f => f.required && !sessionVariables[f.variable_name]?.trim()).length} required variable(s) are still empty. You can fill them now via the Session Variables panel, or complete anyway. Unfilled variables will appear as blank in exports.`}
        confirmLabel="Complete Anyway"
      />

      {/* Session Variables Panel (editable) */}
      {paramsOpen && (
        <div className="fixed inset-0 z-50 flex items-center justify-center">
          <div
            className="absolute inset-0 bg-background/60 backdrop-blur-xs"
            onClick={() => setParamsOpen(false)}
          />
          <div className="relative w-full max-w-md rounded-2xl border border-border bg-card shadow-2xl backdrop-blur-xs">
            <div className="flex items-center justify-between border-b border-border px-5 py-4">
              <h3 className="text-sm font-semibold text-foreground">Session Variables</h3>
              <button
                onClick={() => setParamsOpen(false)}
                className="rounded-lg p-1 text-muted-foreground hover:bg-accent hover:text-foreground"
              >
                <X className="h-4 w-4" />
              </button>
            </div>
            <div className="max-h-[60vh] overflow-y-auto p-5">
              <div className="space-y-2">
                {intakeFields
                  .sort((a, b) => a.display_order - b.display_order)
                  .map((field) => {
                    const value = sessionVariables[field.variable_name] || ''
                    const isFilled = !!value.trim()
                    const isEditing = editingVarName === field.variable_name

                    return (
                      <div
                        key={field.variable_name}
                        className={cn(
                          'rounded-lg border px-3 py-2.5',
                          isFilled ? 'border-border bg-accent' : 'border-cyan-500/20 bg-cyan-500/5'
                        )}
                      >
                        <div className="flex items-center justify-between gap-2">
                          <div className="flex items-center gap-2 min-w-0">
                            {isFilled ? (
                              <Check className="h-3.5 w-3.5 shrink-0 text-emerald-400" />
                            ) : (
                              <AlertCircle className="h-3.5 w-3.5 shrink-0 text-cyan-400" />
                            )}
                            <span className="text-xs font-medium text-muted-foreground truncate">
                              {field.label}
                              {field.required && <span className="ml-1 text-amber-400">*</span>}
                            </span>
                          </div>
                          {!isEditing && (
                            <button
                              onClick={() => startEditingVar(field.variable_name)}
                              className="shrink-0 rounded px-2 py-0.5 text-xs text-muted-foreground hover:bg-card hover:text-foreground"
                            >
                              {isFilled ? 'Edit' : 'Fill'}
                            </button>
                          )}
                        </div>
                        {isEditing ? (
                          <div className="mt-2">
                            {field.field_type === 'select' && field.options?.length ? (
                              <select
                                value={editingVarValue}
                                onChange={(e) => setEditingVarValue(e.target.value)}
                                autoFocus
                                className="w-full rounded-md border border-cyan-500/30 bg-card px-2.5 py-1.5 text-sm text-foreground focus:border-cyan-400 focus:outline-hidden focus:ring-1 focus:ring-cyan-400/30"
                              >
                                <option value="">{field.placeholder || 'Select...'}</option>
                                {field.options.map((opt) => (
                                  <option key={opt} value={opt}>{opt}</option>
                                ))}
                              </select>
                            ) : field.field_type === 'textarea' ? (
                              <textarea
                                value={editingVarValue}
                                onChange={(e) => setEditingVarValue(e.target.value)}
                                autoFocus
                                rows={3}
                                placeholder={field.placeholder}
                                className="w-full rounded-md border border-cyan-500/30 bg-card px-2.5 py-1.5 text-sm text-foreground placeholder:text-muted-foreground focus:border-cyan-400 focus:outline-hidden focus:ring-1 focus:ring-cyan-400/30"
                              />
                            ) : (
                              <input
                                type={field.field_type === 'number' ? 'number' : field.field_type === 'email' ? 'email' : 'text'}
                                value={editingVarValue}
                                onChange={(e) => setEditingVarValue(e.target.value)}
                                onKeyDown={(e) => { if (e.key === 'Enter') saveEditingVar() }}
                                autoFocus
                                placeholder={field.placeholder}
                                className="w-full rounded-md border border-cyan-500/30 bg-card px-2.5 py-1.5 text-sm text-foreground placeholder:text-muted-foreground focus:border-cyan-400 focus:outline-hidden focus:ring-1 focus:ring-cyan-400/30"
                              />
                            )}
                            {field.help_text && (
                              <p className="mt-1 text-[0.625rem] text-muted-foreground">{field.help_text}</p>
                            )}
                            <div className="mt-2 flex justify-end gap-2">
                              <button
                                onClick={() => { setEditingVarName(null); setEditingVarValue('') }}
                                className="rounded px-2.5 py-1 text-xs text-muted-foreground hover:text-foreground"
                              >
                                Cancel
                              </button>
                              <button
                                onClick={saveEditingVar}
                                disabled={!editingVarValue.trim()}
                                className="rounded bg-gradient-brand px-2.5 py-1 text-xs font-medium text-[#101114] disabled:opacity-40"
                              >
                                Save
                              </button>
                            </div>
                          </div>
                        ) : isFilled ? (
                          <p className="mt-1 text-sm text-foreground truncate">{value}</p>
                        ) : null}
                      </div>
                    )
                  })}

                {/* Show any extra variables not in intake form */}
                {Object.entries(sessionVariables)
                  .filter(([key]) => !intakeFields.some(f => f.variable_name === key))
                  .map(([key, value]) => (
                    <div key={key} className="flex items-baseline justify-between gap-4 rounded-lg bg-accent px-3 py-2">
                      <span className="text-xs font-medium text-muted-foreground">{key.replace(/_/g, ' ')}</span>
                      <span className="text-right text-sm text-muted-foreground">{value || 'N/A'}</span>
                    </div>
                  ))}
              </div>
            </div>
          </div>
        </div>
      )}

      {/* Custom Step Modal */}
      <CustomStepModal
        isOpen={showCustomStepModal}
        onClose={() => setShowCustomStepModal(false)}
        onInsertStep={handleStepCreated}
      />

      {/* Post Step Action Modal */}
      {pendingCustomStep && (
        <PostStepActionModal
          isOpen={showPostStepModal}
          onClose={() => { setShowPostStepModal(false); setPendingCustomStep(null) }}
          step={pendingCustomStep}
          onSaveForLater={handleSaveForLater}
          onUseNow={handleUseNow}
          onBoth={handleBoth}
          isFromLibrary={pendingIsFromLibrary}
          isSaving={isSavingStep}
        />
      )}

      {/* AI Copilot toggle button */}
      {treeId && (
        <CopilotToggle isOpen={copilotOpen} onToggle={() => setCopilotOpen(true)} />
      )}

      {/* Ticket Picker Modal */}
      {session && (
        <TicketPickerModal
          open={showTicketPicker}
          onClose={() => setShowTicketPicker(false)}
          sessionId={session.id}
          onLinked={handleTicketLinked}
        />
      )}
    </div>
  )
}

export default ProceduralNavigationPage
