/**
 * TemplatizePrompt — Phase 6 post-resolve modal.
 *
 * Appears after a successful Resolve when ALL three of:
 *   1. account_settings.preferences.templatize_prompt_enabled !== false
 *      (default true when absent — per FLOWPILOT-MIGRATION.md Section 14.2)
 *   2. The session has at least one pending draft_templates row
 *   3. (Implicit from #2) The engineer picked "Run now, templatize after"
 *      on the original three-option dialog
 *
 * The engineer picks a category, optionally tweaks the name/description/
 * parameter list, and either:
 *   - Saves → POST /draft-templates/{id}/accept → new script_templates row
 *   - Skips → POST /draft-templates/{id}/reject
 *   - Toggles "Don't ask me again for this team" → PATCH
 *     /accounts/me/preferences with {templatize_prompt_enabled: false}
 *
 * Parent (AssistantChatPage) controls the open state and feeds one draft at
 * a time. When multiple drafts exist for the session, parent re-opens the
 * modal for the next one after save/skip.
 */
import { useEffect, useMemo, useState } from 'react'
import { Loader2, Check, Trash2, Sparkles } from 'lucide-react'
import { cn } from '@/lib/utils'
import { Modal } from '@/components/common/Modal'
import { toast } from '@/lib/toast'
import { scriptsApi } from '@/api/scripts'
import type { ScriptCategoryResponse } from '@/types'
import {
  draftTemplatesApi,
  accountPreferencesApi,
  type DraftTemplate,
} from '@/api/draftTemplates'
import { ParameterizationPreview } from './ParameterizationPreview'

interface TemplatizePromptProps {
  draft: DraftTemplate
  sourceTicketRef: string | null  // "CW #48307" or null for local-only sessions
  onResolved: (outcome: 'accepted' | 'rejected') => void
}

interface ParamEntry {
  key: string
  label: string
  field_type: string
  inferred_from?: string
}

function normalizeParams(proposed: DraftTemplate['proposed_parameters']): ParamEntry[] {
  const raw = (proposed as { parameters?: unknown[] })?.parameters
  if (!Array.isArray(raw)) return []
  return raw
    .filter((p): p is Record<string, unknown> => typeof p === 'object' && p !== null)
    .map((p) => ({
      key: String(p.key ?? p.variable_name ?? ''),
      label: String(p.label ?? ''),
      field_type: String(p.field_type ?? p.type ?? 'text'),
      inferred_from: typeof p.inferred_from === 'string' ? p.inferred_from : undefined,
    }))
    .filter((p) => p.key.length > 0)
}

export function TemplatizePrompt({ draft, sourceTicketRef, onResolved }: TemplatizePromptProps) {
  const [name, setName] = useState(draft.proposed_name ?? '')
  const [description, setDescription] = useState('')
  const [categoryId, setCategoryId] = useState(draft.proposed_category_id ?? '')
  const [params, setParams] = useState<ParamEntry[]>(() => normalizeParams(draft.proposed_parameters))
  const [dontAskAgain, setDontAskAgain] = useState(false)
  const [categories, setCategories] = useState<ScriptCategoryResponse[]>([])
  const [categoriesLoading, setCategoriesLoading] = useState(true)
  const [saving, setSaving] = useState(false)

  useEffect(() => {
    setCategoriesLoading(true)
    scriptsApi
      .getCategories()
      .then((cats) => {
        setCategories(cats)
        if (!categoryId && cats.length > 0) setCategoryId(cats[0].id)
      })
      .catch(() => toast.error('Could not load script categories'))
      .finally(() => setCategoriesLoading(false))
  }, []) // eslint-disable-line react-hooks/exhaustive-deps

  const canSave = useMemo(
    () => Boolean(name.trim() && categoryId && !saving),
    [name, categoryId, saving],
  )

  const removeParam = (keyToRemove: string) => {
    setParams((prev) => prev.filter((p) => p.key !== keyToRemove))
  }

  const persistOptOutIfNeeded = async () => {
    if (!dontAskAgain) return
    try {
      await accountPreferencesApi.update({ templatize_prompt_enabled: false })
    } catch {
      // Soft-fail: the save itself succeeded; opt-out can be retried from
      // settings. Don't block the engineer on this.
      toast.warning("Could not save 'don't ask again' preference — retry in Settings")
    }
  }

  const handleAccept = async () => {
    if (!canSave) return
    setSaving(true)
    try {
      const parameters_schema = {
        parameters: params.map((p) => ({
          key: p.key,
          label: p.label || p.key,
          field_type: p.field_type,
        })),
      }
      await draftTemplatesApi.accept(draft.id, {
        name: name.trim(),
        category_id: categoryId,
        description: description.trim() || null,
        parameters_schema,
      })
      await persistOptOutIfNeeded()
      toast.success('Saved as team template')
      onResolved('accepted')
    } catch (err: unknown) {
      const status = (err as { response?: { status?: number } })?.response?.status
      if (status === 409) toast.warning('This draft has already been handled')
      else toast.error('Could not save template')
    } finally {
      setSaving(false)
    }
  }

  const handleSkip = async () => {
    setSaving(true)
    try {
      await draftTemplatesApi.reject(draft.id)
      await persistOptOutIfNeeded()
      onResolved('rejected')
    } catch (err: unknown) {
      const status = (err as { response?: { status?: number } })?.response?.status
      if (status === 409) {
        // Already resolved — treat as a no-op, not an error.
        onResolved('rejected')
      } else {
        toast.error('Could not skip draft')
      }
    } finally {
      setSaving(false)
    }
  }

  return (
    <Modal
      isOpen
      onClose={handleSkip}
      title="Save as team template?"
      size="xl"
      footer={
        <div className="flex items-center justify-between gap-3 w-full">
          <label className="flex items-center gap-2 text-[0.75rem] text-muted-foreground cursor-pointer">
            <input
              type="checkbox"
              checked={dontAskAgain}
              onChange={(e) => setDontAskAgain(e.target.checked)}
              className="accent-accent"
            />
            Don't ask me again for this team
          </label>
          <div className="flex items-center gap-2">
            <button
              onClick={handleSkip}
              disabled={saving}
              className="rounded-md px-3 py-1.5 text-[0.8125rem] text-muted-foreground hover:text-heading hover:bg-elevated/40 transition-colors disabled:opacity-40"
            >
              Skip
            </button>
            <button
              onClick={handleAccept}
              disabled={!canSave}
              className={cn(
                'flex items-center gap-1.5 rounded-md px-3 py-1.5 text-[0.8125rem] font-semibold transition-colors',
                canSave
                  ? 'bg-accent text-white hover:bg-accent-hover'
                  : 'bg-elevated text-muted-foreground border border-default cursor-not-allowed',
              )}
            >
              {saving ? <Loader2 size={11} className="animate-spin" /> : <Check size={11} />}
              Save as team template
            </button>
          </div>
        </div>
      }
    >
      <div className="space-y-4 text-[0.8125rem]">
        <div className="flex items-start gap-2 rounded-lg border border-accent/30 bg-accent-dim/15 px-3 py-2">
          <Sparkles size={13} className="text-accent mt-0.5 shrink-0" />
          <div className="text-[0.75rem] text-muted-foreground leading-relaxed">
            This script ran as a one-off during the resolved session
            {sourceTicketRef && (
              <> (<span className="font-mono text-accent-text">{sourceTicketRef}</span>)</>
            )}
            . Review the proposed parameters and save it to the Script Library
            so the team can reuse it.
          </div>
        </div>

        <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
          <div>
            <label className="block text-[0.6875rem] font-semibold text-heading mb-1">
              Template name
            </label>
            <input
              value={name}
              onChange={(e) => setName(e.target.value)}
              className="w-full rounded-md border border-default bg-input px-2.5 py-1.5 text-[0.8125rem] text-heading focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent/30"
              placeholder="Short, descriptive"
            />
          </div>
          <div>
            <label className="block text-[0.6875rem] font-semibold text-heading mb-1">
              Category
            </label>
            <select
              value={categoryId}
              onChange={(e) => setCategoryId(e.target.value)}
              disabled={categoriesLoading}
              className="w-full rounded-md border border-default bg-input px-2.5 py-1.5 text-[0.8125rem] text-heading focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent/30"
            >
              {categoriesLoading && <option>Loading…</option>}
              {!categoriesLoading && categories.length === 0 && (
                <option value="">No categories available</option>
              )}
              {categories.map((c) => (
                <option key={c.id} value={c.id}>{c.name}</option>
              ))}
            </select>
          </div>
        </div>

        <div>
          <label className="block text-[0.6875rem] font-semibold text-heading mb-1">
            Description (optional)
          </label>
          <textarea
            value={description}
            onChange={(e) => setDescription(e.target.value)}
            className="w-full rounded-md border border-default bg-input px-2.5 py-1.5 text-[0.8125rem] text-heading placeholder:text-muted-foreground resize-y min-h-[48px] max-h-[120px] focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent/30"
            rows={2}
            placeholder="What does this script do? When should someone reach for it?"
          />
        </div>

        <div>
          <div className="flex items-center justify-between mb-1">
            <label className="text-[0.6875rem] font-semibold text-heading">
              Proposed parameters ({params.length})
            </label>
            <span className="text-[0.6875rem] text-muted-foreground italic">
              {params.length === 0
                ? 'No parameters proposed — script will run as-is.'
                : 'Remove any that don\'t need to be parameterized.'}
            </span>
          </div>
          {params.length > 0 && (
            <div className="rounded-lg border border-default bg-card overflow-hidden">
              {params.map((p) => (
                <div
                  key={p.key}
                  className="flex items-center gap-2 px-2.5 py-1.5 border-b border-default last:border-b-0"
                >
                  <span className="font-mono text-[0.75rem] text-accent-text">{`{{ ${p.key} }}`}</span>
                  <span className="text-[0.75rem] text-heading">{p.label}</span>
                  <span className="text-[0.625rem] uppercase tracking-wider text-muted-foreground font-semibold">
                    {p.field_type}
                  </span>
                  {p.inferred_from && (
                    <span className="text-[0.6875rem] text-muted-foreground italic truncate flex-1 min-w-0">
                      from {p.inferred_from}
                    </span>
                  )}
                  {!p.inferred_from && <span className="flex-1" />}
                  <button
                    onClick={() => removeParam(p.key)}
                    disabled={saving}
                    className="p-1 rounded text-muted-foreground hover:text-danger hover:bg-elevated/40 transition-colors"
                    title="Remove parameter"
                  >
                    <Trash2 size={11} />
                  </button>
                </div>
              ))}
            </div>
          )}
        </div>

        <div>
          <label className="block text-[0.6875rem] font-semibold text-heading mb-1">
            Script preview
          </label>
          <ParameterizationPreview body={draft.script_body} />
        </div>
      </div>
    </Modal>
  )
}

export default TemplatizePrompt
