import { useState } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { Card, CardContent } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Checkbox } from "@/components/ui/checkbox";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Textarea } from "@/components/ui/textarea";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from "@/components/ui/collapsible";
import { Search, Plus, Loader2, Pencil, Trash2, X, Sparkles, ChevronDown } from "lucide-react";
import AiTipBanner from "@/components/ai/AiTipBanner";
import AiCreationAssistant from "@/components/ai/AiCreationAssistant";
import { examsService } from "@/services/exams.service";
import { useToast } from "@/hooks/use-toast";

interface RubricItem {
  id: number;
  name: string;
  skill: string;
  exam_type: string;
  criteria: number;
  criteria_text: string;
  levels: string[];
  created: string;
}

interface CriterionEntry {
  name: string;
  weight: number;
  descriptors: Record<string, string>;
}

const SKILL_OPTIONS = [
  { value: "writing", label: "Writing" },
  { value: "speaking", label: "Speaking" },
];

const EXAM_TYPE_OPTIONS = [
  { value: "academic", label: "Academic" },
  { value: "general_training", label: "General Training" },
  { value: "general_english", label: "General English" },
];

const ALL_CEFR_LEVELS = ["A1", "A2", "B1", "B2", "C1", "C2"];

interface RubricFormState {
  name: string;
  skill: string;
  exam_type: string;
  criteria: CriterionEntry[];
  levels: Set<string>;
}

const emptyCriterion = (levels: Set<string>): CriterionEntry => ({
  name: "",
  weight: 0,
  descriptors: Object.fromEntries([...levels].map((l) => [l, ""])),
});

const emptyForm = (): RubricFormState => ({
  name: "",
  skill: "writing",
  exam_type: "academic",
  criteria: [],
  levels: new Set(ALL_CEFR_LEVELS),
});

function parseCriteriaText(text: string, levels: string[]): CriterionEntry[] {
  if (!text) return [];

  const mapStructured = (arr: unknown[]): CriterionEntry[] =>
    arr.map((c) => {
      const obj = c as Record<string, unknown>;
      return {
        name: String(obj.name || ""),
        weight: Number(obj.weight || 0),
        descriptors:
          typeof obj.descriptors === "object" && obj.descriptors !== null
            ? Object.fromEntries(levels.map((l) => [l, String((obj.descriptors as Record<string, unknown>)[l] || "")]))
            : Object.fromEntries(levels.map((l) => [l, ""])),
      };
    });

  try {
    const parsed = JSON.parse(text);
    // Handle {"criteria": [...]} wrapper (from AI or previous saves)
    if (parsed && typeof parsed === "object" && !Array.isArray(parsed) && Array.isArray(parsed.criteria)) {
      return mapStructured(parsed.criteria);
    }
    if (Array.isArray(parsed)) {
      if (parsed.length > 0 && typeof parsed[0] === "object" && parsed[0] !== null && "name" in parsed[0]) {
        return mapStructured(parsed);
      }
      return parsed.filter(Boolean).map((name) => ({
        name: String(name),
        weight: Math.round(100 / parsed.length),
        descriptors: Object.fromEntries(levels.map((l) => [l, ""])),
      }));
    }
  } catch { /* not JSON */ }

  const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
  if (lines.length === 0) return [];
  return lines.map((name) => ({
    name,
    weight: Math.round(100 / lines.length),
    descriptors: Object.fromEntries(levels.map((l) => [l, ""])),
  }));
}

interface GroupFormState {
  name: string;
  rubric_ids: Set<number>;
}

const emptyGroupForm = (): GroupFormState => ({ name: "", rubric_ids: new Set() });

export default function RubricsPage() {
  const { toast } = useToast();
  const queryClient = useQueryClient();
  const [search, setSearch] = useState("");

  const [createOpen, setCreateOpen] = useState(false);
  const [createForm, setCreateForm] = useState<RubricFormState>(emptyForm());

  const [editTarget, setEditTarget] = useState<RubricItem | null>(null);
  const [editForm, setEditForm] = useState<RubricFormState>(emptyForm());

  const [groupCreateOpen, setGroupCreateOpen] = useState(false);
  const [groupCreateForm, setGroupCreateForm] = useState<GroupFormState>(emptyGroupForm());
  const [groupEditTarget, setGroupEditTarget] = useState<{ id: number; name: string; rubric_ids: number[] } | null>(null);
  const [groupEditForm, setGroupEditForm] = useState<GroupFormState>(emptyGroupForm());

  const rubricsQ = useQuery({
    queryKey: ["rubrics"],
    queryFn: () => examsService.listRubrics({}),
  });
  const rubrics = (rubricsQ.data?.items ?? []) as RubricItem[];

  const rubricGroupsQ = useQuery({
    queryKey: ["rubric-groups"],
    queryFn: () => examsService.listRubricGroups({}),
  });
  const rubricGroups = rubricGroupsQ.data?.items ?? [];

  const createMut = useMutation({
    mutationFn: (data: Record<string, unknown>) => examsService.createRubric(data as never),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["rubrics"] });
      setCreateOpen(false);
      setCreateForm(emptyForm());
      toast({ title: "Rubric created" });
    },
    onError: (err: Error) => toast({ variant: "destructive", title: "Create failed", description: err.message }),
  });

  const updateMut = useMutation({
    mutationFn: ({ id, data }: { id: number; data: Record<string, unknown> }) =>
      examsService.updateRubric(id, data as never),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["rubrics"] });
      setEditTarget(null);
      toast({ title: "Rubric updated" });
    },
    onError: (err: Error) => toast({ variant: "destructive", title: "Update failed", description: err.message }),
  });

  const deleteMut = useMutation({
    mutationFn: (id: number) => examsService.deleteRubric(id),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["rubrics"] });
      toast({ title: "Rubric deleted" });
    },
    onError: (err: Error) => toast({ variant: "destructive", title: "Delete failed", description: err.message }),
  });

  const createGroupMut = useMutation({
    mutationFn: (data: { name: string; rubric_ids: number[] }) => examsService.createRubricGroup(data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["rubric-groups"] });
      setGroupCreateOpen(false);
      setGroupCreateForm(emptyGroupForm());
      toast({ title: "Rubric group created" });
    },
    onError: (err: Error) => toast({ variant: "destructive", title: "Create group failed", description: err.message }),
  });

  const updateGroupMut = useMutation({
    mutationFn: ({ id, data }: { id: number; data: { name?: string; rubric_ids?: number[] } }) =>
      examsService.updateRubricGroup(id, data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["rubric-groups"] });
      setGroupEditTarget(null);
      toast({ title: "Rubric group updated" });
    },
    onError: (err: Error) => toast({ variant: "destructive", title: "Update group failed", description: err.message }),
  });

  const deleteGroupMut = useMutation({
    mutationFn: (id: number) => examsService.deleteRubricGroup(id),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["rubric-groups"] });
      toast({ title: "Rubric group deleted" });
    },
    onError: (err: Error) => toast({ variant: "destructive", title: "Delete group failed", description: err.message }),
  });

  const [suggesting, setSuggesting] = useState(false);

  const suggestCriteria = async (
    form: RubricFormState,
    setForm: React.Dispatch<React.SetStateAction<RubricFormState>>,
  ) => {
    setSuggesting(true);
    try {
      const result = await examsService.suggestRubricCriteria({
        name: form.name,
        skill: form.skill,
        exam_type: form.exam_type,
        levels: [...form.levels],
      });
      if (result.criteria && Array.isArray(result.criteria) && result.criteria.length > 0) {
        const levelsArr = [...form.levels];
        const entries: CriterionEntry[] = result.criteria.map((c: unknown) => {
          if (typeof c === "object" && c !== null) {
            const obj = c as Record<string, unknown>;
            return {
              name: String(obj.name || ""),
              weight: Number(obj.weight || 0),
              descriptors: typeof obj.descriptors === "object" && obj.descriptors !== null
                ? Object.fromEntries(
                    levelsArr.map((l) => [l, String((obj.descriptors as Record<string, unknown>)[l] || "")])
                  )
                : Object.fromEntries(levelsArr.map((l) => [l, ""])),
            };
          }
          return { name: String(c), weight: 0, descriptors: Object.fromEntries(levelsArr.map((l) => [l, ""])) };
        });
        setForm((f) => ({ ...f, criteria: entries }));
        toast({ title: "Criteria generated", description: `${entries.length} criteria with band descriptors created by AI.` });
      }
    } catch (err) {
      toast({ variant: "destructive", title: "AI suggestion failed", description: (err as Error).message });
    } finally {
      setSuggesting(false);
    }
  };

  const openEdit = (r: RubricItem) => {
    const levelsArr = Array.isArray(r.levels) && r.levels.length > 0 ? r.levels : ALL_CEFR_LEVELS;
    setEditTarget(r);
    setEditForm({
      name: r.name,
      skill: r.skill || "writing",
      exam_type: r.exam_type || "academic",
      criteria: parseCriteriaText(r.criteria_text, levelsArr),
      levels: new Set(levelsArr),
    });
  };

  const formToPayload = (form: RubricFormState) => ({
    name: form.name.trim(),
    skill: form.skill,
    exam_type: form.exam_type,
    criteria: JSON.stringify(form.criteria.filter((c) => c.name.trim())),
    levels: [...form.levels],
  });

  const filtered = rubrics.filter((r) => {
    if (!search) return true;
    const q = search.toLowerCase();
    return r.name?.toLowerCase().includes(q) || r.skill?.toLowerCase().includes(q);
  });

  const updateCriterion = (
    setForm: React.Dispatch<React.SetStateAction<RubricFormState>>,
    index: number,
    patch: Partial<CriterionEntry>,
  ) => {
    setForm((f) => {
      const criteria = [...f.criteria];
      criteria[index] = { ...criteria[index], ...patch };
      return { ...f, criteria };
    });
  };

  const updateDescriptor = (
    setForm: React.Dispatch<React.SetStateAction<RubricFormState>>,
    cIndex: number,
    level: string,
    value: string,
  ) => {
    setForm((f) => {
      const criteria = [...f.criteria];
      criteria[cIndex] = {
        ...criteria[cIndex],
        descriptors: { ...criteria[cIndex].descriptors, [level]: value },
      };
      return { ...f, criteria };
    });
  };

  const renderForm = (
    form: RubricFormState,
    setForm: React.Dispatch<React.SetStateAction<RubricFormState>>,
  ) => {
    const levelsArr = [...form.levels].sort(
      (a, b) => ALL_CEFR_LEVELS.indexOf(a) - ALL_CEFR_LEVELS.indexOf(b)
    );
    const totalWeight = form.criteria.reduce((s, c) => s + (c.weight || 0), 0);

    return (
      <div className="space-y-4">
        <div className="space-y-2">
          <Label>Rubric Name <span className="text-destructive">*</span></Label>
          <Input
            value={form.name}
            onChange={(e) => setForm((f) => ({ ...f, name: e.target.value }))}
            placeholder="e.g. IELTS Writing Task 1"
          />
        </div>
        <div className="grid grid-cols-2 gap-4">
          <div className="space-y-2">
            <Label>Skill</Label>
            <Select value={form.skill} onValueChange={(v) => setForm((f) => ({ ...f, skill: v }))}>
              <SelectTrigger><SelectValue /></SelectTrigger>
              <SelectContent>
                {SKILL_OPTIONS.map((o) => (
                  <SelectItem key={o.value} value={o.value}>{o.label}</SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <div className="space-y-2">
            <Label>Exam Type</Label>
            <Select value={form.exam_type} onValueChange={(v) => setForm((f) => ({ ...f, exam_type: v }))}>
              <SelectTrigger><SelectValue /></SelectTrigger>
              <SelectContent>
                {EXAM_TYPE_OPTIONS.map((o) => (
                  <SelectItem key={o.value} value={o.value}>{o.label}</SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
        </div>

        <div className="space-y-2">
          <Label>CEFR Levels</Label>
          <div className="flex flex-wrap gap-2">
            {ALL_CEFR_LEVELS.map((level) => {
              const checked = form.levels.has(level);
              return (
                <label
                  key={level}
                  className={`flex items-center gap-1.5 rounded-md border px-3 py-1.5 cursor-pointer transition-all text-sm font-medium ${
                    checked ? "bg-primary/10 border-primary text-primary" : "hover:bg-muted/50"
                  }`}
                >
                  <Checkbox
                    checked={checked}
                    onCheckedChange={(val) => {
                      setForm((f) => {
                        const next = new Set(f.levels);
                        if (val) next.add(level); else next.delete(level);
                        return { ...f, levels: next };
                      });
                    }}
                  />
                  {level}
                </label>
              );
            })}
          </div>
        </div>

        <div className="space-y-3">
          <div className="flex items-center justify-between">
            <div>
              <Label>Criteria</Label>
              {form.criteria.length > 0 && (
                <span className={`ml-2 text-xs ${totalWeight === 100 ? "text-green-600" : "text-amber-600"}`}>
                  (Total weight: {totalWeight}%)
                </span>
              )}
            </div>
            <Button
              type="button"
              size="sm"
              className="h-8 bg-gradient-to-r from-violet-500 to-indigo-500 text-white hover:from-violet-600 hover:to-indigo-600"
              disabled={suggesting}
              onClick={() => suggestCriteria(form, setForm)}
            >
              {suggesting
                ? <><Loader2 className="h-3.5 w-3.5 mr-1.5 animate-spin" /> Generating...</>
                : <><Sparkles className="h-3.5 w-3.5 mr-1.5" /> Generate with AI</>
              }
            </Button>
          </div>

          {suggesting ? (
            <div className="flex flex-col items-center justify-center py-8 gap-2 text-muted-foreground rounded-lg border border-dashed border-violet-300 bg-violet-50/50">
              <Loader2 className="h-6 w-6 animate-spin text-violet-500" />
              <p className="text-sm font-medium">AI is generating criteria with band descriptors...</p>
              <p className="text-xs">Based on {form.skill} / {form.exam_type.replace(/_/g, " ")}</p>
            </div>
          ) : form.criteria.length === 0 ? (
            <div className="flex flex-col items-center justify-center py-8 gap-2 text-muted-foreground rounded-lg border border-dashed">
              <Sparkles className="h-5 w-5 text-violet-400" />
              <p className="text-sm">No criteria yet.</p>
              <p className="text-xs">Click <strong>Generate with AI</strong> to create criteria automatically, or add manually.</p>
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="mt-1"
                onClick={() => setForm((f) => ({ ...f, criteria: [...f.criteria, emptyCriterion(f.levels)] }))}
              >
                <Plus className="h-3 w-3 mr-1" /> Add Manually
              </Button>
            </div>
          ) : (
            <div className="space-y-3">
              {form.criteria.map((c, ci) => (
                <Collapsible key={ci} defaultOpen={form.criteria.length <= 3}>
                  <div className="rounded-lg border bg-card">
                    <div className="flex items-center gap-2 p-3">
                      <CollapsibleTrigger asChild>
                        <Button variant="ghost" size="icon" className="h-7 w-7 shrink-0">
                          <ChevronDown className="h-4 w-4" />
                        </Button>
                      </CollapsibleTrigger>
                      <Input
                        value={c.name}
                        onChange={(e) => updateCriterion(setForm, ci, { name: e.target.value })}
                        placeholder="Criterion name"
                        className="flex-1 h-8 font-medium"
                      />
                      <div className="flex items-center gap-1 shrink-0">
                        <Input
                          type="number"
                          min={0}
                          max={100}
                          value={c.weight}
                          onChange={(e) => updateCriterion(setForm, ci, { weight: Number(e.target.value) })}
                          className="w-16 h-8 text-center text-sm"
                        />
                        <span className="text-xs text-muted-foreground">%</span>
                      </div>
                      <Button
                        type="button"
                        variant="ghost"
                        size="icon"
                        className="h-7 w-7 shrink-0 text-muted-foreground hover:text-destructive"
                        onClick={() => setForm((f) => ({ ...f, criteria: f.criteria.filter((_, i) => i !== ci) }))}
                      >
                        <X className="h-4 w-4" />
                      </Button>
                    </div>
                    <CollapsibleContent>
                      <div className="px-3 pb-3 pt-0 border-t">
                        <p className="text-xs text-muted-foreground my-2">Band level descriptors:</p>
                        <div className="space-y-2">
                          {levelsArr.map((level) => (
                            <div key={level} className="flex gap-2 items-start">
                              <Badge variant="outline" className="mt-1.5 shrink-0 w-9 justify-center text-xs">{level}</Badge>
                              <Textarea
                                value={c.descriptors[level] || ""}
                                onChange={(e) => updateDescriptor(setForm, ci, level, e.target.value)}
                                placeholder={`Performance descriptor for ${level}...`}
                                className="min-h-[40px] h-10 text-sm resize-none"
                              />
                            </div>
                          ))}
                        </div>
                      </div>
                    </CollapsibleContent>
                  </div>
                </Collapsible>
              ))}
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="w-full"
                onClick={() => setForm((f) => ({ ...f, criteria: [...f.criteria, emptyCriterion(f.levels)] }))}
              >
                <Plus className="h-3 w-3 mr-1" /> Add Criterion
              </Button>
            </div>
          )}
        </div>
      </div>
    );
  };

  return (
    <div className="space-y-6">
      <div className="flex items-center justify-between">
        <div>
          <h1 className="text-2xl font-bold tracking-tight">Rubrics</h1>
          <p className="text-muted-foreground">Create and manage evaluation rubrics with level-based descriptors.</p>
        </div>
        <div className="flex gap-2">
          <AiCreationAssistant type="rubric" />
          <Dialog open={createOpen} onOpenChange={(open) => { setCreateOpen(open); if (!open) setCreateForm(emptyForm()); }}>
            <DialogTrigger asChild>
              <Button size="sm"><Plus className="h-4 w-4 mr-1" /> Create Rubric</Button>
            </DialogTrigger>
            <DialogContent className="max-w-2xl max-h-[85vh] overflow-y-auto">
              <DialogHeader>
                <DialogTitle>Create Rubric</DialogTitle>
                <DialogDescription>Define a scoring rubric. Use AI to generate criteria or add them manually.</DialogDescription>
              </DialogHeader>
              {renderForm(createForm, setCreateForm)}
              <DialogFooter>
                <Button variant="outline" onClick={() => setCreateOpen(false)}>Cancel</Button>
                <Button
                  disabled={!createForm.name.trim() || createForm.criteria.filter((c) => c.name.trim()).length === 0 || createMut.isPending}
                  onClick={() => createMut.mutate(formToPayload(createForm))}
                >
                  {createMut.isPending ? <><Loader2 className="h-4 w-4 animate-spin mr-2" />Creating...</> : "Create"}
                </Button>
              </DialogFooter>
            </DialogContent>
          </Dialog>
        </div>
      </div>

      <AiTipBanner context="rubrics" variant="recommendation" />

      <div className="relative max-w-sm">
        <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
        <Input placeholder="Search rubrics..." className="pl-9" value={search} onChange={(e) => setSearch(e.target.value)} />
      </div>

      <Tabs defaultValue="rubrics">
        <TabsList>
          <TabsTrigger value="rubrics">Rubrics List</TabsTrigger>
          <TabsTrigger value="groups">Rubric Groups</TabsTrigger>
        </TabsList>
        <TabsContent value="rubrics" className="mt-4">
          {rubricsQ.isLoading && (
            <div className="flex items-center justify-center py-12">
              <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
            </div>
          )}
          {rubricsQ.error && (
            <Card className="border-destructive">
              <CardContent className="p-4 text-sm text-destructive">
                Failed to load rubrics. The backend endpoint may not be available yet.
              </CardContent>
            </Card>
          )}
          {!rubricsQ.isLoading && !rubricsQ.error && filtered.length === 0 && (
            <Card className="border-dashed">
              <CardContent className="p-8 text-center text-muted-foreground">
                No rubrics found. Create one to get started.
              </CardContent>
            </Card>
          )}
          {!rubricsQ.isLoading && filtered.length > 0 && (
            <Card className="border-0 shadow-sm">
              <CardContent className="p-0">
                <Table>
                  <TableHeader>
                    <TableRow>
                      <TableHead>Name</TableHead>
                      <TableHead>Skill</TableHead>
                      <TableHead>Exam Type</TableHead>
                      <TableHead>Levels</TableHead>
                      <TableHead>Criteria</TableHead>
                      <TableHead>Created</TableHead>
                      <TableHead className="w-[90px]">Actions</TableHead>
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {filtered.map((r) => (
                      <TableRow key={r.id} className="cursor-pointer hover:bg-muted/50" onClick={() => openEdit(r)}>
                        <TableCell className="font-medium">{r.name}</TableCell>
                        <TableCell><Badge variant="secondary" className="capitalize">{r.skill || "—"}</Badge></TableCell>
                        <TableCell className="capitalize text-sm">{r.exam_type?.replace(/_/g, " ") || "—"}</TableCell>
                        <TableCell>
                          <div className="flex gap-1">
                            {(r.levels || ALL_CEFR_LEVELS).map((l) => (
                              <Badge key={l} variant="outline" className="text-xs">{l}</Badge>
                            ))}
                          </div>
                        </TableCell>
                        <TableCell>{r.criteria}</TableCell>
                        <TableCell className="text-sm text-muted-foreground">{r.created}</TableCell>
                        <TableCell>
                          <div className="flex gap-1">
                            <Button variant="ghost" size="icon" className="h-8 w-8"
                              onClick={(e) => { e.stopPropagation(); openEdit(r); }}>
                              <Pencil className="h-4 w-4" />
                            </Button>
                            <Button variant="ghost" size="icon" className="h-8 w-8 text-destructive"
                              onClick={(e) => { e.stopPropagation(); deleteMut.mutate(r.id); }}
                              disabled={deleteMut.isPending}>
                              <Trash2 className="h-4 w-4" />
                            </Button>
                          </div>
                        </TableCell>
                      </TableRow>
                    ))}
                  </TableBody>
                </Table>
              </CardContent>
            </Card>
          )}
        </TabsContent>
        <TabsContent value="groups" className="mt-4">
          <div className="flex justify-end mb-3">
            <Button size="sm" onClick={() => { setGroupCreateForm(emptyGroupForm()); setGroupCreateOpen(true); }}>
              <Plus className="h-4 w-4 mr-1" /> Create Group
            </Button>
          </div>
          {rubricGroupsQ.isLoading && (
            <div className="flex justify-center py-8"><Loader2 className="h-6 w-6 animate-spin text-muted-foreground" /></div>
          )}
          {!rubricGroupsQ.isLoading && rubricGroups.length === 0 && (
            <Card className="border-dashed"><CardContent className="p-8 text-center text-muted-foreground text-sm">No rubric groups yet. Create one to bundle rubrics together.</CardContent></Card>
          )}
          {!rubricGroupsQ.isLoading && rubricGroups.length > 0 && (
            <Card className="border-0 shadow-sm">
              <CardContent className="p-0">
                <Table>
                  <TableHeader>
                    <TableRow>
                      <TableHead>Group Name</TableHead>
                      <TableHead>Rubrics</TableHead>
                      <TableHead>Created</TableHead>
                      <TableHead className="w-24 text-right">Actions</TableHead>
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {rubricGroups.map((g) => (
                      <TableRow key={g.id}>
                        <TableCell className="font-medium">{g.name}</TableCell>
                        <TableCell>
                          <div className="flex gap-1 flex-wrap">
                            {(g.rubric_names ?? []).map((rb) => (
                              <Badge key={rb} variant="secondary" className="text-xs">{rb}</Badge>
                            ))}
                            {(!g.rubric_names || g.rubric_names.length === 0) && (
                              <span className="text-xs text-muted-foreground italic">No rubrics</span>
                            )}
                          </div>
                        </TableCell>
                        <TableCell>{g.created}</TableCell>
                        <TableCell className="text-right">
                          <div className="flex justify-end gap-1">
                            <Button variant="ghost" size="icon" className="h-7 w-7" onClick={() => {
                              setGroupEditTarget({ id: g.id, name: g.name, rubric_ids: g.rubric_ids });
                              setGroupEditForm({ name: g.name, rubric_ids: new Set(g.rubric_ids) });
                            }}>
                              <Pencil className="h-3.5 w-3.5" />
                            </Button>
                            <Button variant="ghost" size="icon" className="h-7 w-7 text-destructive hover:text-destructive"
                              onClick={() => { if (confirm(`Delete group "${g.name}"?`)) deleteGroupMut.mutate(g.id); }}>
                              <Trash2 className="h-3.5 w-3.5" />
                            </Button>
                          </div>
                        </TableCell>
                      </TableRow>
                    ))}
                  </TableBody>
                </Table>
              </CardContent>
            </Card>
          )}

          {/* Create Group Dialog */}
          <Dialog open={groupCreateOpen} onOpenChange={setGroupCreateOpen}>
            <DialogContent className="max-w-md">
              <DialogHeader>
                <DialogTitle>Create Rubric Group</DialogTitle>
                <DialogDescription>Bundle multiple rubrics into a group for easy selection.</DialogDescription>
              </DialogHeader>
              <div className="space-y-4 py-2">
                <div className="space-y-1">
                  <Label>Group Name <span className="text-destructive">*</span></Label>
                  <Input value={groupCreateForm.name} onChange={(e) => setGroupCreateForm((p) => ({ ...p, name: e.target.value }))} placeholder="e.g. Academic IELTS Full" />
                </div>
                <div className="space-y-1">
                  <Label>Select Rubrics</Label>
                  <div className="max-h-48 overflow-y-auto border rounded-md p-2 space-y-1">
                    {rubrics.map((r) => (
                      <label key={r.id} className="flex items-center gap-2 text-sm cursor-pointer hover:bg-muted/50 rounded px-1 py-0.5">
                        <Checkbox checked={groupCreateForm.rubric_ids.has(r.id)}
                          onCheckedChange={(checked) => {
                            setGroupCreateForm((p) => {
                              const next = new Set(p.rubric_ids);
                              checked ? next.add(r.id) : next.delete(r.id);
                              return { ...p, rubric_ids: next };
                            });
                          }} className="h-3.5 w-3.5" />
                        {r.name}
                        <Badge variant="outline" className="text-[10px] ml-auto">{r.skill}</Badge>
                      </label>
                    ))}
                    {rubrics.length === 0 && <p className="text-xs text-muted-foreground italic py-2 text-center">No rubrics available</p>}
                  </div>
                </div>
              </div>
              <DialogFooter>
                <Button variant="outline" onClick={() => setGroupCreateOpen(false)}>Cancel</Button>
                <Button disabled={!groupCreateForm.name.trim() || createGroupMut.isPending}
                  onClick={() => createGroupMut.mutate({ name: groupCreateForm.name.trim(), rubric_ids: [...groupCreateForm.rubric_ids] })}>
                  {createGroupMut.isPending ? <><Loader2 className="h-4 w-4 animate-spin mr-2" />Creating...</> : "Create Group"}
                </Button>
              </DialogFooter>
            </DialogContent>
          </Dialog>

          {/* Edit Group Dialog */}
          <Dialog open={!!groupEditTarget} onOpenChange={(open) => { if (!open) setGroupEditTarget(null); }}>
            <DialogContent className="max-w-md">
              <DialogHeader>
                <DialogTitle>Edit Rubric Group</DialogTitle>
                <DialogDescription>Update the group name and selected rubrics.</DialogDescription>
              </DialogHeader>
              <div className="space-y-4 py-2">
                <div className="space-y-1">
                  <Label>Group Name <span className="text-destructive">*</span></Label>
                  <Input value={groupEditForm.name} onChange={(e) => setGroupEditForm((p) => ({ ...p, name: e.target.value }))} />
                </div>
                <div className="space-y-1">
                  <Label>Select Rubrics</Label>
                  <div className="max-h-48 overflow-y-auto border rounded-md p-2 space-y-1">
                    {rubrics.map((r) => (
                      <label key={r.id} className="flex items-center gap-2 text-sm cursor-pointer hover:bg-muted/50 rounded px-1 py-0.5">
                        <Checkbox checked={groupEditForm.rubric_ids.has(r.id)}
                          onCheckedChange={(checked) => {
                            setGroupEditForm((p) => {
                              const next = new Set(p.rubric_ids);
                              checked ? next.add(r.id) : next.delete(r.id);
                              return { ...p, rubric_ids: next };
                            });
                          }} className="h-3.5 w-3.5" />
                        {r.name}
                        <Badge variant="outline" className="text-[10px] ml-auto">{r.skill}</Badge>
                      </label>
                    ))}
                  </div>
                </div>
              </div>
              <DialogFooter>
                <Button variant="outline" onClick={() => setGroupEditTarget(null)}>Cancel</Button>
                <Button disabled={!groupEditForm.name.trim() || updateGroupMut.isPending}
                  onClick={() => {
                    if (!groupEditTarget) return;
                    updateGroupMut.mutate({ id: groupEditTarget.id, data: { name: groupEditForm.name.trim(), rubric_ids: [...groupEditForm.rubric_ids] } });
                  }}>
                  {updateGroupMut.isPending ? <><Loader2 className="h-4 w-4 animate-spin mr-2" />Saving...</> : "Save Changes"}
                </Button>
              </DialogFooter>
            </DialogContent>
          </Dialog>
        </TabsContent>
      </Tabs>

      <Dialog open={!!editTarget} onOpenChange={(open) => { if (!open) setEditTarget(null); }}>
        <DialogContent className="max-w-2xl max-h-[85vh] overflow-y-auto">
          <DialogHeader>
            <DialogTitle>Edit Rubric</DialogTitle>
            <DialogDescription>Update the rubric details below. Use AI to regenerate criteria.</DialogDescription>
          </DialogHeader>
          {renderForm(editForm, setEditForm)}
          <DialogFooter>
            <Button variant="outline" onClick={() => setEditTarget(null)}>Cancel</Button>
            <Button
              disabled={!editForm.name.trim() || editForm.criteria.filter((c) => c.name.trim()).length === 0 || updateMut.isPending}
              onClick={() => {
                if (!editTarget) return;
                updateMut.mutate({ id: editTarget.id, data: formToPayload(editForm) });
              }}
            >
              {updateMut.isPending ? <><Loader2 className="h-4 w-4 animate-spin mr-2" />Saving...</> : "Save Changes"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
