import { useState } from "react"
import {
  CheckCircle2,
  ChevronDown,
  CircleSlash,
  Loader2,
  Save,
  ShieldCheck,
  Sparkles,
  Trash2,
  Wand2,
} from "lucide-react"
import { useDashboard } from "@/lib/dashboard"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { Badge } from "@/components/ui/badge"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Label } from "@/components/ui/label"
import { Switch } from "@/components/ui/switch"
import { cn } from "@/lib/utils"
import type {
  ActionSpec,
  AutomationDocument,
  AutomationRule,
  ConditionBlock,
  CooldownCondition,
} from "@/lib/types"

export function RuleStudioPanel() {
  const {
    rulesText,
    setRulesText,
    replaceRulesText,
    validate,
    validation,
    save,
    setRuleEnabled,
    deleteRule,
    compiler,
    compile,
    compiling,
  } = useDashboard()
  const [instruction, setInstruction] = useState(
    "When a cat appears in the image, notify me.",
  )
  const [armedDelete, setArmedDelete] = useState<string | null>(null)
  const [expandedRule, setExpandedRule] = useState<string | null>(null)
  const document = validation?.ok ? validation.document : null

  const applyDocument = (nextDocument: AutomationDocument) => {
    void replaceRulesText(JSON.stringify(nextDocument, null, 2), true)
  }

  const updateRule = (ruleIndex: number, updater: (rule: AutomationRule) => void) => {
    if (!document) return
    const nextDocument = cloneDocument(document)
    const rule = nextDocument.rules[ruleIndex]
    if (!rule) return
    updater(rule)
    applyDocument(nextDocument)
  }

  return (
    <Tabs defaultValue="compose">
      <div className="flex items-center justify-between">
        <TabsList>
          <TabsTrigger value="compose">
            <Sparkles className="size-3.5" />
            Compose
          </TabsTrigger>
          <TabsTrigger value="source">Source</TabsTrigger>
          <TabsTrigger value="rules">
            Rules
            {validation?.ok && (
              <span className="ml-1 font-mono text-[0.625rem] text-muted-foreground">
                {validation.rules.length}
              </span>
            )}
          </TabsTrigger>
        </TabsList>
        {validation &&
          (validation.ok ? (
            <Badge variant="live">
              <CheckCircle2 className="size-3" />
              valid
            </Badge>
          ) : (
            <Badge variant="danger">
              <CircleSlash className="size-3" />
              invalid
            </Badge>
          ))}
      </div>

      {/* Compose: NL → rules */}
      <TabsContent value="compose">
        <div className="space-y-3">
          <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
            <p className="text-xs text-muted-foreground">
              Describe the automation in plain language. It compiles to validated rules through{" "}
              {compiler.provider} — never executable code.
            </p>
            <Badge variant="default">{compiler.provider}</Badge>
          </div>
          <Textarea
            value={instruction}
            onChange={(e) => setInstruction(e.target.value)}
            className="min-h-24"
            placeholder="When a cat is near the feeder, dispense food once every 30 minutes…"
          />
          <Button onClick={() => compile(instruction)} disabled={compiling || !instruction.trim()}>
            {compiling ? <Loader2 className="size-4 animate-spin" /> : <Wand2 className="size-4" />}
            {compiling
              ? "Compiling…"
              : `Compile with ${compiler.provider}`}
          </Button>
        </div>
      </TabsContent>

      {/* Source: raw editor */}
      <TabsContent value="source">
        <div className="space-y-3">
          <div className="relative">
            <div className="absolute left-0 top-0 z-10 rounded-br-md rounded-tl-md border-b border-r border-border bg-black/40 px-2 py-0.5 font-mono text-[0.625rem] uppercase tracking-wider text-muted-foreground">
              yaml · json
            </div>
            <Textarea
              value={rulesText}
              onChange={(e) => setRulesText(e.target.value)}
              spellCheck={false}
              className="min-h-64 bg-black/40 pt-7 font-mono text-xs leading-relaxed"
            />
          </div>
          {validation && !validation.ok && validation.error && (
            <pre className="max-h-28 overflow-auto rounded-md border border-destructive/30 bg-destructive/5 p-3 font-mono text-[0.6875rem] text-destructive/90 whitespace-pre-wrap">
              {validation.error}
            </pre>
          )}
          <div className="flex gap-2">
            <Button variant="secondary" onClick={validate}>
              <ShieldCheck className="size-4" />
              Validate
            </Button>
            <Button variant="secondary" onClick={save}>
              <Save className="size-4" />
              Save
            </Button>
          </div>
        </div>
      </TabsContent>

      {/* Rules: parsed view */}
      <TabsContent value="rules">
        {validation?.ok && document && document.rules.length > 0 ? (
          <div className="space-y-2">
            {document.rules.map((rule, ruleIndex) => {
              const r = validation.rules.find((item) => item.name === rule.name) ?? {
                name: rule.name,
                enabled: rule.gate.enabled,
                trigger: rule.trigger.on,
                labels: [],
                conditions: rule.when.all.length + rule.when.any.length,
                actions: ruleActions(rule).map((action) => ({ type: action.type, name: action.name })),
              }
              const expanded = expandedRule === rule.name
              return (
              <div
                key={r.name}
                className="rounded-lg border border-border bg-black/20"
              >
                <button
                  type="button"
                  className="flex w-full flex-col gap-3 px-4 py-3 text-left sm:flex-row sm:items-center sm:justify-between"
                  onClick={() => setExpandedRule(expanded ? null : rule.name)}
                >
                  <div className="min-w-0">
                    <div className="flex items-center gap-2">
                      <ChevronDown
                        className={cn(
                          "size-4 shrink-0 text-muted-foreground transition-transform",
                          expanded && "rotate-180 text-primary",
                        )}
                      />
                      <span
                        className={cn(
                          "size-1.5 rounded-full",
                          r.enabled ? "bg-primary" : "bg-muted-foreground/40",
                        )}
                      />
                      <span className="truncate font-mono text-sm text-foreground">{r.name}</span>
                      {r.name.startsWith("example-") && <Badge variant="default">example</Badge>}
                      <Badge variant="default">{r.trigger}</Badge>
                    </div>
                    <div className="mt-1 pl-9 text-xs text-muted-foreground">
                      {r.conditions} condition{r.conditions === 1 ? "" : "s"} →{" "}
                      {r.actions.map((a) => `${a.type}:${a.name}`).join(", ")}
                    </div>
                    {r.labels.length > 0 && (
                      <div className="mt-2 flex flex-wrap gap-1 pl-9">
                        {r.labels.map((label) => (
                          <span
                            key={label}
                            className="rounded border border-border bg-black/30 px-1.5 py-0.5 font-mono text-[0.625rem] text-muted-foreground"
                          >
                            {label}
                          </span>
                        ))}
                      </div>
                    )}
                  </div>
                  <div className="flex shrink-0 items-center gap-2" onClick={(event) => event.stopPropagation()}>
                    <Label htmlFor={`enabled-${r.name}`} className="text-xs text-muted-foreground">
                      {r.enabled ? "enabled" : "disabled"}
                    </Label>
                    <Switch
                      id={`enabled-${r.name}`}
                      checked={r.enabled}
                      onCheckedChange={(checked) => setRuleEnabled(r.name, checked)}
                    />
                    <Button
                      variant={armedDelete === r.name ? "destructive" : "secondary"}
                      size="sm"
                      onClick={() => {
                        if (armedDelete === r.name) {
                          void deleteRule(r.name)
                          setArmedDelete(null)
                        } else {
                          setArmedDelete(r.name)
                        }
                      }}
                    >
                      <Trash2 className="size-4" />
                      {armedDelete === r.name ? "Confirm" : "Delete"}
                    </Button>
                  </div>
                </button>
                {expanded && (
                  <RuleEditor
                    rule={rule}
                    onUpdate={(updater) => updateRule(ruleIndex, updater)}
                  />
                )}
              </div>
            )})}
          </div>
        ) : validation?.ok ? (
          <div className="flex flex-col items-center gap-2 py-8 text-center text-muted-foreground">
            <ShieldCheck className="size-7 opacity-40" />
            <p className="text-sm">No rules saved.</p>
          </div>
        ) : (
          <div className="flex flex-col items-center gap-2 py-8 text-center text-muted-foreground">
            <ShieldCheck className="size-7 opacity-40" />
            <p className="text-sm">Validate the source to see parsed rules.</p>
            <Button variant="secondary" size="sm" onClick={validate}>
              Validate now
            </Button>
          </div>
        )}
      </TabsContent>
    </Tabs>
  )
}

function RuleEditor({
  rule,
  onUpdate,
}: {
  rule: AutomationRule
  onUpdate: (updater: (rule: AutomationRule) => void) => void
}) {
  return (
    <div className="border-t border-border px-4 pb-4 pt-3">
      <div className="grid gap-3 lg:grid-cols-2">
        <div className="space-y-3">
          <div className="flex items-center justify-between rounded-md border border-border bg-black/20 px-3 py-2">
            <div>
              <div className="text-xs font-medium text-foreground">Cooldown</div>
              <div className="text-[0.6875rem] text-muted-foreground">Blocks repeated fires for this rule.</div>
            </div>
            <Switch
              checked={Boolean(rule.gate.cooldown)}
              onCheckedChange={(checked) =>
                onUpdate((draft) => {
                  draft.gate.cooldown = checked ? { key: draft.name, seconds: null, minutes: 5 } : null
                })
              }
            />
          </div>
          {rule.gate.cooldown && (
            <CooldownEditor
              cooldown={rule.gate.cooldown}
              onChange={(next) => onUpdate((draft) => { draft.gate.cooldown = next })}
            />
          )}
          <ConditionList
            title="All conditions"
            conditions={rule.when.all}
            onUpdate={(conditionIndex, updater) =>
              onUpdate((draft) => {
                const condition = draft.when.all[conditionIndex]
                if (condition) updater(condition)
              })
            }
          />
          {rule.when.any.length > 0 && (
            <ConditionList
              title="Any conditions"
              conditions={rule.when.any}
              onUpdate={(conditionIndex, updater) =>
                onUpdate((draft) => {
                  const condition = draft.when.any[conditionIndex]
                  if (condition) updater(condition)
                })
              }
            />
          )}
        </div>
        <div className="space-y-3">
          <ActionList
            rule={rule}
            onUpdate={(bucket, actionIndex, updater) =>
              onUpdate((draft) => {
                updateRuleAction(draft, bucket, actionIndex, updater)
              })
            }
          />
          <div className="rounded-md border border-border bg-black/20 p-3 text-[0.6875rem] text-muted-foreground">
            Global webhooks still act as the master safety switch. Per-rule webhook actions can carry their own URL.
          </div>
        </div>
      </div>
    </div>
  )
}

function ConditionList({
  title,
  conditions,
  onUpdate,
}: {
  title: string
  conditions: ConditionBlock[]
  onUpdate: (conditionIndex: number, updater: (condition: ConditionBlock) => void) => void
}) {
  return (
    <div className="space-y-2">
      <div className="font-mono text-[0.625rem] uppercase tracking-wider text-muted-foreground">{title}</div>
      {conditions.map((condition, index) => (
        <ConditionEditor
          key={index}
          condition={condition}
          onUpdate={(updater) => onUpdate(index, updater)}
        />
      ))}
    </div>
  )
}

function ConditionEditor({
  condition,
  onUpdate,
}: {
  condition: ConditionBlock
  onUpdate: (updater: (condition: ConditionBlock) => void) => void
}) {
  if (condition.present) {
    return (
      <EditorBlock label="present">
        <ReadOnlyField label="label" value={condition.present.label} />
        <NumberField label="min count" value={condition.present.min_count} min={1} step={1} onChange={(value) => onUpdate((draft) => { draft.present!.min_count = Math.max(1, Math.round(value)) })} />
      </EditorBlock>
    )
  }
  if (condition.count) {
    return (
      <EditorBlock label="count">
        <ReadOnlyField label="label" value={condition.count.label} />
        <NumberField label="minimum" value={condition.count.minimum} min={1} step={1} onChange={(value) => onUpdate((draft) => { draft.count!.minimum = Math.max(1, Math.round(value)) })} />
      </EditorBlock>
    )
  }
  if (condition.near) {
    return (
      <EditorBlock label="near">
        <ReadOnlyField label="a" value={condition.near.a} />
        <ReadOnlyField label="b" value={condition.near.b} />
        <NumberField label="max gap %" value={condition.near.max_gap_percent} min={0} step={1} onChange={(value) => onUpdate((draft) => { draft.near!.max_gap_percent = value })} />
      </EditorBlock>
    )
  }
  if (condition.far) {
    return (
      <EditorBlock label="far">
        <ReadOnlyField label="a" value={condition.far.a} />
        <ReadOnlyField label="b" value={condition.far.b} />
        <NumberField label="min gap %" value={condition.far.min_gap_percent} min={0} step={1} onChange={(value) => onUpdate((draft) => { draft.far!.min_gap_percent = value })} />
      </EditorBlock>
    )
  }
  if (condition.moving) {
    return (
      <EditorBlock label="moving">
        <ReadOnlyField label="label" value={condition.moving.label} />
        <NumberField label="min move (×size)" value={condition.moving.min_displacement_ratio} min={0} step={0.05} onChange={(value) => onUpdate((draft) => { draft.moving!.min_displacement_ratio = value })} />
        <NumberField label="frames" value={condition.moving.window_frames} min={3} step={1} onChange={(value) => onUpdate((draft) => { draft.moving!.window_frames = Math.max(3, Math.round(value)) })} />
        <NumberField label="misses" value={condition.moving.max_missing_frames} min={0} step={1} onChange={(value) => onUpdate((draft) => { draft.moving!.max_missing_frames = Math.max(0, Math.round(value)) })} />
      </EditorBlock>
    )
  }
  if (condition.cooldown) {
    return (
      <EditorBlock label="cooldown">
        <CooldownEditor cooldown={condition.cooldown} onChange={(next) => onUpdate((draft) => { draft.cooldown = next })} />
      </EditorBlock>
    )
  }
  return null
}

function CooldownEditor({
  cooldown,
  onChange,
}: {
  cooldown: CooldownCondition
  onChange: (next: CooldownCondition) => void
}) {
  return (
    <div className="grid gap-2 sm:grid-cols-3">
      <TextField label="key" value={cooldown.key ?? ""} onChange={(value) => onChange({ ...cooldown, key: value || null })} />
      <OptionalNumberField label="seconds" value={cooldown.seconds} onChange={(value) => onChange({ ...cooldown, seconds: value, minutes: null })} />
      <OptionalNumberField label="minutes" value={cooldown.minutes} onChange={(value) => onChange({ ...cooldown, minutes: value, seconds: null })} />
    </div>
  )
}

function ActionList({
  rule,
  onUpdate,
}: {
  rule: AutomationRule
  onUpdate: (bucket: ActionBucket, actionIndex: number, updater: (action: ActionSpec) => void) => void
}) {
  const actions = editableActions(rule)
  return (
    <div className="space-y-2">
      <div className="font-mono text-[0.625rem] uppercase tracking-wider text-muted-foreground">Actions</div>
      {actions.map(({ action, bucket, actionIndex, label }) => (
        <EditorBlock key={`${bucket}-${actionIndex}`} label={label}>
          <TextField label="name" value={action.name} onChange={(value) => onUpdate(bucket, actionIndex, (draft) => { draft.name = value })} />
          <div className="space-y-1">
            <Label className="text-[0.6875rem] text-muted-foreground">type</Label>
            <select
              value={action.type}
              onChange={(event) => onUpdate(bucket, actionIndex, (draft) => { draft.type = event.target.value as ActionSpec["type"] })}
              className="h-9 w-full rounded-md border border-input bg-black/20 px-3 text-sm text-foreground focus-visible:outline-none focus-visible:border-primary/50 focus-visible:ring-2 focus-visible:ring-ring"
            >
              <option value="simulate">simulate</option>
              <option value="webhook">webhook</option>
            </select>
          </div>
          {action.type === "webhook" && (
            <TextField label="url" value={action.url ?? ""} onChange={(value) => onUpdate(bucket, actionIndex, (draft) => { draft.url = value || null })} />
          )}
        </EditorBlock>
      ))}
    </div>
  )
}

function EditorBlock({ label, children }: { label: string; children: React.ReactNode }) {
  return (
    <div className="rounded-md border border-border bg-black/20 p-3">
      <div className="mb-2 font-mono text-[0.625rem] uppercase tracking-wider text-primary">{label}</div>
      <div className="grid gap-2 sm:grid-cols-2">{children}</div>
    </div>
  )
}

function TextField({ label, value, onChange }: { label: string; value: string; onChange: (value: string) => void }) {
  return (
    <div className="space-y-1">
      <Label className="text-[0.6875rem] text-muted-foreground">{label}</Label>
      <Input value={value} onChange={(event) => onChange(event.target.value)} />
    </div>
  )
}

function ReadOnlyField({ label, value }: { label: string; value: string }) {
  return (
    <div className="space-y-1">
      <Label className="text-[0.6875rem] text-muted-foreground">{label}</Label>
      <div className="flex h-9 items-center rounded-md border border-border bg-black/30 px-3 font-mono text-xs text-muted-foreground">
        {value}
      </div>
    </div>
  )
}

function NumberField({
  label,
  value,
  min,
  step,
  onChange,
}: {
  label: string
  value: number
  min?: number
  step?: number
  onChange: (value: number) => void
}) {
  return (
    <div className="space-y-1">
      <Label className="text-[0.6875rem] text-muted-foreground">{label}</Label>
      <Input
        type="number"
        value={Number.isFinite(value) ? value : 0}
        min={min}
        step={step}
        onChange={(event) => onChange(Number(event.target.value || 0))}
      />
    </div>
  )
}

function OptionalNumberField({
  label,
  value,
  onChange,
}: {
  label: string
  value: number | null
  onChange: (value: number | null) => void
}) {
  return (
    <div className="space-y-1">
      <Label className="text-[0.6875rem] text-muted-foreground">{label}</Label>
      <Input
        type="number"
        value={value ?? ""}
        min={0}
        step={1}
        onChange={(event) => onChange(event.target.value === "" ? null : Number(event.target.value))}
      />
    </div>
  )
}

type ActionBucket = "then" | "enter" | "exit" | "while"

function editableActions(rule: AutomationRule): Array<{
  bucket: ActionBucket
  actionIndex: number
  label: string
  action: ActionSpec
}> {
  if (Array.isArray(rule.then)) {
    return rule.then.map((action, actionIndex) => ({ bucket: "then", actionIndex, label: "then", action }))
  }
  return [
    ...rule.then.enter.map((action, actionIndex) => ({ bucket: "enter" as const, actionIndex, label: "enter", action })),
    ...rule.then.exit.map((action, actionIndex) => ({ bucket: "exit" as const, actionIndex, label: "exit", action })),
    ...rule.then.while.map((action, actionIndex) => ({ bucket: "while" as const, actionIndex, label: "while", action })),
  ]
}

function ruleActions(rule: AutomationRule): ActionSpec[] {
  return editableActions(rule).map((item) => item.action)
}

function updateRuleAction(
  rule: AutomationRule,
  bucket: ActionBucket,
  actionIndex: number,
  updater: (action: ActionSpec) => void,
) {
  if (Array.isArray(rule.then)) {
    const action = rule.then[actionIndex]
    if (action) updater(action)
    return
  }
  const action = rule.then[bucket === "then" ? "enter" : bucket][actionIndex]
  if (action) updater(action)
}

function cloneDocument(document: AutomationDocument): AutomationDocument {
  return JSON.parse(JSON.stringify(document)) as AutomationDocument
}
