"use client";

import * as React from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { useSession } from "next-auth/react";
import { Plus, Pencil, Trash2, Building2, Layers, Tags, CalendarRange } from "lucide-react";
import { apiGet, apiSend } from "@/lib/api";
import type { KpiDTO, CompanyDTO, DepartmentDTO, UserDTO, ChannelDTO } from "@/lib/types";
import { can } from "@/lib/rbac";
import { formatMetric } from "@/lib/utils";
import { PERIOD_LABEL, KPI_CATEGORY_LABEL } from "@/lib/labels";

const CATEGORIES = [
  "ACQUISITION", "CONVERSION", "REVENUE", "SPEND", "ENGAGEMENT", "BRAND", "OUTPUT", "OTHER",
];
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Select } from "@/components/ui/select";
import { Label } from "@/components/ui/label";
import { Badge } from "@/components/ui/badge";
import { Progress } from "@/components/ui/progress";
import { Dialog, DialogHeader, DialogBody, DialogFooter } from "@/components/ui/dialog";
import { InfoHint } from "@/components/ui/info-hint";
import { PageHeader, Spinner, EmptyState } from "@/components/common";

const PERIODS = ["WEEKLY", "MONTHLY", "QUARTERLY"];
const MONTHS = [
  "January", "February", "March", "April", "May", "June",
  "July", "August", "September", "October", "November", "December",
];
// Resolve a KPI's target, actual & remark for the selected month, falling back
// to the KPI's default target when no monthly value has been entered.
function resolveMonth(k: KpiDTO): { target: number; actual: number; note: string | null } {
  const mv = k.monthlyValues?.[0];
  return {
    target: mv?.targetValue ?? k.targetValue,
    actual: mv?.actualValue ?? 0,
    note: mv?.note ?? null,
  };
}

export function KpiView() {
  const { data: session } = useSession();
  const canWrite = can(session?.user?.role, "kpis:write");
  const qc = useQueryClient();

  // Selected calendar month for monthly KPI tracking (defaults to this month).
  const today = new Date();
  const [year, setYear] = React.useState(today.getFullYear());
  const [month, setMonth] = React.useState(today.getMonth() + 1);

  const kpisQuery = useQuery({
    queryKey: ["kpis", year, month],
    queryFn: () => apiGet<KpiDTO[]>(`/api/kpis?year=${year}&month=${month}`),
  });
  const companiesQuery = useQuery({
    queryKey: ["companies"],
    queryFn: () => apiGet<CompanyDTO[]>("/api/companies"),
  });
  const departmentsQuery = useQuery({
    queryKey: ["departments"],
    queryFn: () => apiGet<DepartmentDTO[]>("/api/departments"),
  });
  const channelsQuery = useQuery({
    queryKey: ["channels"],
    queryFn: () => apiGet<ChannelDTO[]>("/api/channels"),
  });
  const usersQuery = useQuery({
    queryKey: ["users"],
    queryFn: () => apiGet<UserDTO[]>("/api/users"),
    enabled: canWrite,
  });

  const [open, setOpen] = React.useState(false);
  const [editing, setEditing] = React.useState<KpiDTO | null>(null);
  const [companiesOpen, setCompaniesOpen] = React.useState(false);
  const [departmentsOpen, setDepartmentsOpen] = React.useState(false);
  const [channelsOpen, setChannelsOpen] = React.useState(false);
  // The KPI whose monthly value is being edited (null = closed).
  const [monthEditing, setMonthEditing] = React.useState<KpiDTO | null>(null);
  const years = [today.getFullYear() - 1, today.getFullYear(), today.getFullYear() + 1];

  const del = useMutation({
    mutationFn: (id: string) => apiSend(`/api/kpis/${id}`, "DELETE"),
    onSuccess: () => qc.invalidateQueries({ queryKey: ["kpis"] }),
  });

  const kpis = kpisQuery.data ?? [];
  const companies = companiesQuery.data ?? [];
  const departments = departmentsQuery.data ?? [];
  const channels = channelsQuery.data ?? [];
  const dept = kpis.filter((k) => k.type === "DEPARTMENT");
  const personal = kpis.filter((k) => k.type === "PERSONAL");

  // Group department KPIs by company (FR-1). KPIs with no company fall into a
  // trailing "Unassigned" bucket.
  const deptByCompany = groupByCompany(dept, companies);

  return (
    <div>
      <PageHeader title="KPI Indicators" subtitle="Define company department & personal performance metrics">
        {canWrite && (
          <>
            <Button variant="secondary" onClick={() => setCompaniesOpen(true)}>
              <Building2 className="size-4" /> Companies
            </Button>
            <Button variant="secondary" onClick={() => setDepartmentsOpen(true)}>
              <Layers className="size-4" /> Departments
            </Button>
            <Button variant="secondary" onClick={() => setChannelsOpen(true)}>
              <Tags className="size-4" /> Channels
            </Button>
            <Button
              onClick={() => {
                setEditing(null);
                setOpen(true);
              }}
            >
              <Plus className="size-4" /> New Indicator
            </Button>
          </>
        )}
      </PageHeader>

      {/* Month selector — KPI targets & actuals are tracked per calendar month. */}
      <Card className="mb-4">
        <CardContent className="flex flex-wrap items-center gap-3 py-3">
          <span className="text-sm font-medium">Tracking month:</span>
          <Select
            value={String(month)}
            onChange={(e) => setMonth(Number(e.target.value))}
            className="w-auto"
          >
            {MONTHS.map((m, i) => (
              <option key={m} value={i + 1}>
                {m}
              </option>
            ))}
          </Select>
          <Select
            value={String(year)}
            onChange={(e) => setYear(Number(e.target.value))}
            className="w-auto"
          >
            {years.map((y) => (
              <option key={y} value={y}>
                {y}
              </option>
            ))}
          </Select>
          <span className="text-xs text-muted-foreground">
            Showing each KPI&apos;s target &amp; actual for {MONTHS[month - 1]} {year}.
          </span>
        </CardContent>
      </Card>

      {kpisQuery.isLoading ? (
        <Spinner />
      ) : (
        <div className="space-y-6">
          <Card>
            <CardHeader>
              <CardTitle>Department KPIs</CardTitle>
              <p className="text-xs text-muted-foreground">
                Goals grouped by the company they belong to
              </p>
            </CardHeader>
            <CardContent className="space-y-5">
              {dept.length === 0 ? (
                <EmptyState title="No department indicators yet" />
              ) : (
                deptByCompany.map((group) => (
                  <div key={group.key}>
                    <div className="mb-2 flex items-center gap-2">
                      <Building2 className="size-4 text-muted-foreground" />
                      <span className="text-sm font-semibold">{group.name}</span>
                      <Badge variant="outline">{group.kpis.length}</Badge>
                    </div>
                    <KpiGrid
                      kpis={group.kpis}
                      canWrite={canWrite}
                      onEdit={(k) => {
                        setEditing(k);
                        setOpen(true);
                      }}
                      onDelete={(id) => del.mutate(id)}
                      onUpdateMonth={(k) => setMonthEditing(k)}
                    />
                  </div>
                ))
              )}
            </CardContent>
          </Card>

          <Card>
            <CardHeader>
              <CardTitle>Personal KPIs</CardTitle>
              <p className="text-xs text-muted-foreground">
                Targets assigned to individual staff members
              </p>
            </CardHeader>
            <CardContent>
              {personal.length === 0 ? (
                <EmptyState title="No personal indicators yet" />
              ) : (
                <KpiGrid
                  kpis={personal}
                  canWrite={canWrite}
                  showAssignee
                  onEdit={(k) => {
                    setEditing(k);
                    setOpen(true);
                  }}
                  onDelete={(id) => del.mutate(id)}
                  onUpdateMonth={(k) => setMonthEditing(k)}
                />
              )}
            </CardContent>
          </Card>
        </div>
      )}

      {canWrite && (
        <>
          <KpiDialog
            open={open}
            onClose={() => setOpen(false)}
            onSaved={() => qc.invalidateQueries({ queryKey: ["kpis"] })}
            kpi={editing}
            companies={companies}
            departments={departments}
            users={usersQuery.data ?? []}
            channels={channels}
          />
          <CompaniesDialog
            open={companiesOpen}
            onClose={() => setCompaniesOpen(false)}
            companies={companies}
          />
          <DepartmentsDialog
            open={departmentsOpen}
            onClose={() => setDepartmentsOpen(false)}
            departments={departments}
          />
          <ChannelsDialog
            open={channelsOpen}
            onClose={() => setChannelsOpen(false)}
            channels={channels}
          />
          <MonthlyValueDialog
            kpi={monthEditing}
            year={year}
            month={month}
            onClose={() => setMonthEditing(null)}
            onSaved={() => qc.invalidateQueries({ queryKey: ["kpis"] })}
          />
        </>
      )}
    </div>
  );
}

function groupByCompany(dept: KpiDTO[], companies: CompanyDTO[]) {
  const groups: { key: string; name: string; kpis: KpiDTO[] }[] = [];
  for (const c of companies) {
    const kpis = dept.filter((k) => k.companyId === c.id);
    if (kpis.length) groups.push({ key: c.id, name: c.name, kpis });
  }
  const orphans = dept.filter((k) => !k.companyId || !companies.some((c) => c.id === k.companyId));
  if (orphans.length) groups.push({ key: "_none", name: "Unassigned", kpis: orphans });
  return groups;
}

function KpiGrid({
  kpis,
  canWrite,
  showAssignee,
  onEdit,
  onDelete,
  onUpdateMonth,
}: {
  kpis: KpiDTO[];
  canWrite: boolean;
  showAssignee?: boolean;
  onEdit: (k: KpiDTO) => void;
  onDelete: (id: string) => void;
  onUpdateMonth: (k: KpiDTO) => void;
}) {
  return (
    <div className="grid gap-3 md:grid-cols-2">
      {kpis.map((k) => {
        const { target, actual, note } = resolveMonth(k);
        const pct = target ? Math.min(100, Math.round((actual / target) * 100)) : 0;
        const flagged = pct < 60;
        return (
          <div key={k.id} className="rounded-md border border-border p-3">
            <div className="mb-1 flex items-start justify-between gap-2">
              <div>
                <div className="flex items-center gap-1.5 text-sm font-semibold">
                  {k.name}
                  {k.description && <InfoHint text={k.description} />}
                </div>
                <div className="mt-0.5 flex flex-wrap gap-1.5">
                  <Badge variant="outline">{PERIOD_LABEL[k.period]}</Badge>
                  {k.department && <Badge variant="primary">{k.department.name}</Badge>}
                  {k.category && k.category !== "OTHER" && (
                    <Badge>{KPI_CATEGORY_LABEL[k.category] ?? k.category}</Badge>
                  )}
                  {showAssignee && k.assignedUser && (
                    <Badge variant="primary">{k.assignedUser.name}</Badge>
                  )}
                  {k.channels?.map((ch) => (
                    <Badge key={ch.id} variant="outline">
                      {ch.name}
                    </Badge>
                  ))}
                  {k.weightage > 0 && <Badge>{k.weightage}% weight</Badge>}
                </div>
              </div>
              {canWrite && (
                <div className="flex shrink-0 gap-1">
                  <Button variant="ghost" size="icon" onClick={() => onEdit(k)} title="Edit definition">
                    <Pencil className="size-3.5" />
                  </Button>
                  <Button variant="ghost" size="icon" onClick={() => onDelete(k.id)} title="Delete">
                    <Trash2 className="size-3.5" />
                  </Button>
                </div>
              )}
            </div>
            <div className="mb-1 flex items-center justify-between text-xs text-muted-foreground">
              <span>
                {formatMetric(actual, k.unit)} / {formatMetric(target, k.unit)}
              </span>
              <span>{pct}%</span>
            </div>
            <Progress value={pct} />
            {note && (
              <div
                className={
                  "mt-2 rounded-md border px-2 py-1.5 text-[11px] " +
                  (flagged
                    ? "border-warning/40 bg-warning/10 text-warning"
                    : "border-border bg-secondary/50 text-muted-foreground")
                }
              >
                <span className="font-semibold">Remark: </span>
                {note}
              </div>
            )}
            {canWrite && (
              <div className="mt-2 flex justify-end">
                <Button variant="outline" size="sm" onClick={() => onUpdateMonth(k)}>
                  <CalendarRange className="size-3.5" /> Update this month
                </Button>
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
}

function KpiDialog({
  open,
  onClose,
  onSaved,
  kpi,
  companies,
  departments,
  users,
  channels,
}: {
  open: boolean;
  onClose: () => void;
  onSaved: () => void;
  kpi: KpiDTO | null;
  companies: CompanyDTO[];
  departments: DepartmentDTO[];
  users: UserDTO[];
  channels: ChannelDTO[];
}) {
  const [form, setForm] = React.useState(() => initForm(kpi));
  const [error, setError] = React.useState("");

  React.useEffect(() => {
    setForm(initForm(kpi));
    setError("");
  }, [kpi, open]);

  // Staff are the assignable owners of a personal KPI.
  const staff = users.filter((u) => u.role === "STAFF");
  const activeCompanies = companies.filter((c) => c.active);
  const activeDepartments = departments.filter((d) => d.active);
  const activeChannels = channels.filter((c) => c.active);

  function toggleChannel(id: string) {
    setForm((f) => ({
      ...f,
      channelIds: f.channelIds.includes(id)
        ? f.channelIds.filter((x) => x !== id)
        : [...f.channelIds, id],
    }));
  }

  const save = useMutation({
    mutationFn: async () => {
      const payload = {
        name: form.name,
        description: form.description || null,
        type: form.type,
        category: form.category,
        targetValue: Number(form.targetValue),
        unit: form.unit,
        period: form.period,
        companyId: form.type === "DEPARTMENT" ? form.companyId || null : null,
        departmentId: form.departmentId || null,
        assignedUserId: form.type === "PERSONAL" ? form.assignedUserId || null : null,
        channelIds: form.channelIds,
        weightage: Number(form.weightage) || 0,
      };
      return kpi
        ? apiSend(`/api/kpis/${kpi.id}`, "PATCH", payload)
        : apiSend("/api/kpis", "POST", payload);
    },
    onSuccess: () => {
      onSaved();
      onClose();
    },
    onError: (e) => setError(e instanceof Error ? e.message : "Failed to save"),
  });

  function submit(e: React.FormEvent) {
    e.preventDefault();
    if (!form.name.trim()) return setError("Name is required");
    if (!form.unit.trim()) return setError("Unit is required");
    if (form.type === "PERSONAL" && !form.assignedUserId)
      return setError("Personal KPIs must be assigned to a staff member");
    save.mutate();
  }

  return (
    <Dialog open={open} onClose={onClose}>
      <DialogHeader title={kpi ? "Edit Indicator" : "New Indicator"} onClose={onClose} />
      <form onSubmit={submit}>
        <DialogBody>
          <div className="space-y-1.5">
            <Label>Name</Label>
            <Input
              value={form.name}
              onChange={(e) => setForm({ ...form, name: e.target.value })}
              placeholder="e.g. Cost Per Lead, Designs per Month"
              autoFocus
            />
          </div>
          <div className="space-y-1.5">
            <Label className="flex items-center gap-1.5">
              Description
              <InfoHint text="Explain what this KPI measures and how it's counted, in plain language. This text appears behind the '!' on the KPI card and the staff member's dashboard ring, so they understand what to work toward." />
            </Label>
            <Textarea
              value={form.description}
              onChange={(e) => setForm({ ...form, description: e.target.value })}
              placeholder="e.g. Number of finished videos published this month (Reels + YouTube). Counts one per approved, posted video."
            />
          </div>
          <div className="grid grid-cols-2 gap-3">
            <div className="space-y-1.5">
              <Label className="flex items-center gap-1.5">
                Type
                <InfoHint text="Department = a team goal that rolls up to a company (shown on Reports & the Executive area). Personal = assigned to one staff member and shown on their dashboard rings." />
              </Label>
              <Select value={form.type} onChange={(e) => setForm({ ...form, type: e.target.value })}>
                <option value="DEPARTMENT">Department</option>
                <option value="PERSONAL">Personal</option>
              </Select>
            </div>
            <div className="space-y-1.5">
              <Label className="flex items-center gap-1.5">
                Tracking cycle
                <InfoHint text="How often this KPI is measured (Weekly / Monthly / Quarterly). Targets and actuals are still recorded per calendar month; this is the intended cadence." />
              </Label>
              <Select value={form.period} onChange={(e) => setForm({ ...form, period: e.target.value })}>
                {PERIODS.map((p) => (
                  <option key={p} value={p}>
                    {PERIOD_LABEL[p]}
                  </option>
                ))}
              </Select>
            </div>
            <div className="col-span-2 space-y-1.5">
              <Label className="flex items-center gap-1.5">
                Category (business area)
                <InfoHint text="Groups the KPI by business area (Acquisition, Conversion, Revenue, Spend, Engagement, Brand, Output, Other) for the 'KPI attainment by area' panels and reports." />
              </Label>
              <Select value={form.category} onChange={(e) => setForm({ ...form, category: e.target.value })}>
                {CATEGORIES.map((c) => (
                  <option key={c} value={c}>
                    {KPI_CATEGORY_LABEL[c]}
                  </option>
                ))}
              </Select>
            </div>

            <div className="col-span-2 space-y-1.5">
              <Label className="flex items-center gap-1.5">
                Department
                <InfoHint text="The functional team that owns this KPI (Marketing, Admin, Finance, Operations, HQ). Drives the department filters on the Dashboard, Reports and Weekly Log. HQ (all-access) shows under every filter." />
              </Label>
              <Select
                value={form.departmentId}
                onChange={(e) => setForm({ ...form, departmentId: e.target.value })}
              >
                <option value="">— No department —</option>
                {activeDepartments.map((d) => (
                  <option key={d.id} value={d.id}>
                    {d.name}
                  </option>
                ))}
              </Select>
              {activeDepartments.length === 0 && (
                <p className="text-xs text-muted-foreground">
                  Add a department first with the “Departments” button.
                </p>
              )}
            </div>

            {form.type === "DEPARTMENT" && (
              <div className="col-span-2 space-y-1.5">
                <Label className="flex items-center gap-1.5">
                  Company
                  <InfoHint text="Which company/brand this department KPI belongs to (e.g. Optimum Swim School, Optimum Fit). Used to group KPIs and scope the company filters." />
                </Label>
                <Select
                  value={form.companyId}
                  onChange={(e) => setForm({ ...form, companyId: e.target.value })}
                >
                  <option value="">— No company —</option>
                  {activeCompanies.map((c) => (
                    <option key={c.id} value={c.id}>
                      {c.name}
                    </option>
                  ))}
                </Select>
                {activeCompanies.length === 0 && (
                  <p className="text-xs text-muted-foreground">
                    Add a company first with the “Companies” button.
                  </p>
                )}
              </div>
            )}

            {form.type === "PERSONAL" && (
              <div className="col-span-2 space-y-1.5">
                <Label>Assigned staff member</Label>
                <Select
                  value={form.assignedUserId}
                  onChange={(e) => setForm({ ...form, assignedUserId: e.target.value })}
                >
                  <option value="">— Select staff —</option>
                  {staff.map((u) => (
                    <option key={u.id} value={u.id}>
                      {u.name}
                      {u.position ? ` · ${u.position}` : ""}
                    </option>
                  ))}
                </Select>
              </div>
            )}

            <div className="space-y-1.5">
              <Label className="flex items-center gap-1.5">
                Default monthly target
                <InfoHint text="The goal value used for any month where you haven't set a specific monthly target via 'Update this month'. Attainment % = actual ÷ target." />
              </Label>
              <Input
                type="number"
                step="any"
                value={form.targetValue}
                onChange={(e) => setForm({ ...form, targetValue: e.target.value })}
              />
              <p className="text-[11px] text-muted-foreground">
                Used for any month you haven&apos;t set a specific target.
              </p>
            </div>
            <div className="space-y-1.5">
              <Label className="flex items-center gap-1.5">
                Unit
                <InfoHint text="How the value is expressed — e.g. RM (money), % (rate), Count (number of items), x (multiplier). Shown next to the numbers everywhere." />
              </Label>
              <Input
                value={form.unit}
                onChange={(e) => setForm({ ...form, unit: e.target.value })}
                placeholder="RM, %, Count, x"
              />
            </div>
            <div className="space-y-1.5">
              <Label className="flex items-center gap-1.5">
                Weightage (%)
                <InfoHint text="How much this KPI counts toward the weighted Team Score. Higher weight = bigger influence. Leave 0 if it shouldn't affect the overall score." />
              </Label>
              <Input
                type="number"
                min="0"
                max="100"
                value={form.weightage}
                onChange={(e) => setForm({ ...form, weightage: e.target.value })}
              />
            </div>
            <div className="col-span-2 space-y-1.5">
              <Label className="flex items-center gap-1.5">
                Channels (optional)
                <InfoHint text="Marketing channels this KPI relates to (Meta, Google, TikTok, SEO…). A KPI can span several; used for channel filtering in reports." />
              </Label>
              {activeChannels.length === 0 ? (
                <p className="text-xs text-muted-foreground">
                  No channels yet. Add them with the “Channels” button.
                </p>
              ) : (
                <div className="flex flex-wrap gap-2">
                  {activeChannels.map((ch) => {
                    const on = form.channelIds.includes(ch.id);
                    return (
                      <button
                        key={ch.id}
                        type="button"
                        onClick={() => toggleChannel(ch.id)}
                        className={
                          "rounded-full border px-3 py-1 text-xs font-medium transition-colors " +
                          (on
                            ? "border-primary bg-primary text-primary-foreground"
                            : "border-border bg-card text-muted-foreground hover:bg-secondary")
                        }
                      >
                        {on ? "✓ " : ""}
                        {ch.name}
                      </button>
                    );
                  })}
                </div>
              )}
              <p className="text-[11px] text-muted-foreground">
                Tap each channel that applies — a KPI can span several.
              </p>
            </div>
          </div>
          {error && <p className="text-sm text-destructive">{error}</p>}
        </DialogBody>
        <DialogFooter>
          <Button type="button" variant="secondary" onClick={onClose}>
            Cancel
          </Button>
          <Button type="submit" disabled={save.isPending}>
            {kpi ? "Save changes" : "Create indicator"}
          </Button>
        </DialogFooter>
      </form>
    </Dialog>
  );
}

// Inline manager for companies (FR-1) — add, rename, activate, delete.
function CompaniesDialog({
  open,
  onClose,
  companies,
}: {
  open: boolean;
  onClose: () => void;
  companies: CompanyDTO[];
}) {
  const qc = useQueryClient();
  const [name, setName] = React.useState("");
  const [error, setError] = React.useState("");
  // Inline rename state — which company is being edited and its draft name.
  const [editingId, setEditingId] = React.useState<string | null>(null);
  const [editName, setEditName] = React.useState("");

  const refresh = () => qc.invalidateQueries({ queryKey: ["companies"] });

  const create = useMutation({
    mutationFn: () => apiSend("/api/companies", "POST", { name }),
    onSuccess: () => {
      setName("");
      setError("");
      refresh();
    },
    onError: (e) => setError(e instanceof Error ? e.message : "Failed to add"),
  });
  const rename = useMutation({
    mutationFn: (vars: { id: string; name: string }) =>
      apiSend(`/api/companies/${vars.id}`, "PATCH", { name: vars.name }),
    onSuccess: () => {
      setEditingId(null);
      setError("");
      refresh();
    },
    onError: (e) => setError(e instanceof Error ? e.message : "Failed to rename"),
  });
  const toggle = useMutation({
    mutationFn: (c: CompanyDTO) => apiSend(`/api/companies/${c.id}`, "PATCH", { active: !c.active }),
    onSuccess: refresh,
  });
  const remove = useMutation({
    mutationFn: (id: string) => apiSend(`/api/companies/${id}`, "DELETE"),
    onSuccess: refresh,
  });

  function startEdit(c: CompanyDTO) {
    setEditingId(c.id);
    setEditName(c.name);
    setError("");
  }

  return (
    <Dialog open={open} onClose={onClose}>
      <DialogHeader title="Companies" onClose={onClose} />
      <DialogBody>
        <p className="text-xs text-muted-foreground">
          Companies that department KPIs roll up to.
        </p>
        <div className="flex gap-2">
          <Input
            value={name}
            onChange={(e) => setName(e.target.value)}
            placeholder="New company name"
            onKeyDown={(e) => {
              if (e.key === "Enter" && name.trim()) {
                e.preventDefault();
                create.mutate();
              }
            }}
          />
          <Button type="button" onClick={() => name.trim() && create.mutate()} disabled={create.isPending}>
            <Plus className="size-4" /> Add
          </Button>
        </div>
        {error && <p className="text-sm text-destructive">{error}</p>}
        <div className="space-y-1.5">
          {companies.length === 0 ? (
            <EmptyState title="No companies yet" />
          ) : (
            companies.map((c) =>
              editingId === c.id ? (
                <div
                  key={c.id}
                  className="flex items-center gap-2 rounded-md border border-primary px-3 py-2"
                >
                  <Input
                    value={editName}
                    onChange={(e) => setEditName(e.target.value)}
                    autoFocus
                    onKeyDown={(e) => {
                      if (e.key === "Enter" && editName.trim())
                        rename.mutate({ id: c.id, name: editName.trim() });
                      if (e.key === "Escape") setEditingId(null);
                    }}
                  />
                  <Button
                    type="button"
                    size="sm"
                    disabled={!editName.trim() || rename.isPending}
                    onClick={() => rename.mutate({ id: c.id, name: editName.trim() })}
                  >
                    Save
                  </Button>
                  <Button type="button" variant="ghost" size="sm" onClick={() => setEditingId(null)}>
                    Cancel
                  </Button>
                </div>
              ) : (
                <div
                  key={c.id}
                  className="flex items-center justify-between rounded-md border border-border px-3 py-2"
                >
                  <div className="flex items-center gap-2">
                    <span className="text-sm font-medium">{c.name}</span>
                    {!c.active && <Badge variant="outline">Inactive</Badge>}
                  </div>
                  <div className="flex gap-1">
                    <Button variant="ghost" size="icon" onClick={() => startEdit(c)} title="Rename">
                      <Pencil className="size-3.5" />
                    </Button>
                    <Button variant="ghost" size="sm" onClick={() => toggle.mutate(c)}>
                      {c.active ? "Deactivate" : "Activate"}
                    </Button>
                    <Button variant="ghost" size="icon" onClick={() => remove.mutate(c.id)} title="Delete">
                      <Trash2 className="size-3.5" />
                    </Button>
                  </div>
                </div>
              )
            )
          )}
        </div>
      </DialogBody>
      <DialogFooter>
        <Button type="button" variant="secondary" onClick={onClose}>
          Done
        </Button>
      </DialogFooter>
    </Dialog>
  );
}

// Inline manager for departments — add, rename, activate, delete.
function DepartmentsDialog({
  open,
  onClose,
  departments,
}: {
  open: boolean;
  onClose: () => void;
  departments: DepartmentDTO[];
}) {
  const qc = useQueryClient();
  const [name, setName] = React.useState("");
  const [error, setError] = React.useState("");
  const [editingId, setEditingId] = React.useState<string | null>(null);
  const [editName, setEditName] = React.useState("");

  const refresh = () => qc.invalidateQueries({ queryKey: ["departments"] });

  const create = useMutation({
    mutationFn: () => apiSend("/api/departments", "POST", { name }),
    onSuccess: () => {
      setName("");
      setError("");
      refresh();
    },
    onError: (e) => setError(e instanceof Error ? e.message : "Failed to add"),
  });
  const rename = useMutation({
    mutationFn: (vars: { id: string; name: string }) =>
      apiSend(`/api/departments/${vars.id}`, "PATCH", { name: vars.name }),
    onSuccess: () => {
      setEditingId(null);
      setError("");
      refresh();
    },
    onError: (e) => setError(e instanceof Error ? e.message : "Failed to rename"),
  });
  const toggle = useMutation({
    mutationFn: (d: DepartmentDTO) =>
      apiSend(`/api/departments/${d.id}`, "PATCH", { active: !d.active }),
    onSuccess: refresh,
  });
  const toggleSpan = useMutation({
    mutationFn: (d: DepartmentDTO) =>
      apiSend(`/api/departments/${d.id}`, "PATCH", { spansAll: !d.spansAll }),
    onSuccess: refresh,
  });
  const remove = useMutation({
    mutationFn: (id: string) => apiSend(`/api/departments/${id}`, "DELETE"),
    onSuccess: refresh,
  });

  return (
    <Dialog open={open} onClose={onClose}>
      <DialogHeader title="Departments" onClose={onClose} />
      <DialogBody>
        <p className="text-xs text-muted-foreground">
          Functional teams that own KPIs and staff (e.g. Marketing, Admin, Finance, Operations).
          Mark a department <span className="font-medium">All-access</span> (e.g. HQ) so its KPIs
          &amp; staff appear under every department and company filter.
        </p>
        <div className="flex gap-2">
          <Input
            value={name}
            onChange={(e) => setName(e.target.value)}
            placeholder="e.g. Marketing, Finance, Operations"
            onKeyDown={(e) => {
              if (e.key === "Enter" && name.trim()) {
                e.preventDefault();
                create.mutate();
              }
            }}
          />
          <Button type="button" onClick={() => name.trim() && create.mutate()} disabled={create.isPending}>
            <Plus className="size-4" /> Add
          </Button>
        </div>
        {error && <p className="text-sm text-destructive">{error}</p>}
        <div className="space-y-1.5">
          {departments.length === 0 ? (
            <EmptyState title="No departments yet" />
          ) : (
            departments.map((d) =>
              editingId === d.id ? (
                <div
                  key={d.id}
                  className="flex items-center gap-2 rounded-md border border-primary px-3 py-2"
                >
                  <Input
                    value={editName}
                    onChange={(e) => setEditName(e.target.value)}
                    autoFocus
                    onKeyDown={(e) => {
                      if (e.key === "Enter" && editName.trim())
                        rename.mutate({ id: d.id, name: editName.trim() });
                      if (e.key === "Escape") setEditingId(null);
                    }}
                  />
                  <Button
                    type="button"
                    size="sm"
                    disabled={!editName.trim() || rename.isPending}
                    onClick={() => rename.mutate({ id: d.id, name: editName.trim() })}
                  >
                    Save
                  </Button>
                  <Button type="button" variant="ghost" size="sm" onClick={() => setEditingId(null)}>
                    Cancel
                  </Button>
                </div>
              ) : (
                <div
                  key={d.id}
                  className="flex items-center justify-between rounded-md border border-border px-3 py-2"
                >
                  <div className="flex items-center gap-2">
                    <span className="text-sm font-medium">{d.name}</span>
                    {d.spansAll && <Badge variant="primary">All-access</Badge>}
                    {!d.active && <Badge variant="outline">Inactive</Badge>}
                  </div>
                  <div className="flex gap-1">
                    <Button
                      variant="ghost"
                      size="icon"
                      onClick={() => {
                        setEditingId(d.id);
                        setEditName(d.name);
                        setError("");
                      }}
                      title="Rename"
                    >
                      <Pencil className="size-3.5" />
                    </Button>
                    <Button
                      variant="ghost"
                      size="sm"
                      onClick={() => toggleSpan.mutate(d)}
                      title="Cross-cutting departments (e.g. HQ) show under every department & company filter"
                    >
                      {d.spansAll ? "Unset all-access" : "All-access"}
                    </Button>
                    <Button variant="ghost" size="sm" onClick={() => toggle.mutate(d)}>
                      {d.active ? "Deactivate" : "Activate"}
                    </Button>
                    <Button variant="ghost" size="icon" onClick={() => remove.mutate(d.id)} title="Delete">
                      <Trash2 className="size-3.5" />
                    </Button>
                  </div>
                </div>
              )
            )
          )}
        </div>
      </DialogBody>
      <DialogFooter>
        <Button type="button" variant="secondary" onClick={onClose}>
          Done
        </Button>
      </DialogFooter>
    </Dialog>
  );
}

// Set a KPI's target & actual for the selected calendar month.
function MonthlyValueDialog({
  kpi,
  year,
  month,
  onClose,
  onSaved,
}: {
  kpi: KpiDTO | null;
  year: number;
  month: number;
  onClose: () => void;
  onSaved: () => void;
}) {
  const open = !!kpi;
  const [target, setTarget] = React.useState("");
  const [actual, setActual] = React.useState("");
  const [note, setNote] = React.useState("");
  const [error, setError] = React.useState("");

  React.useEffect(() => {
    if (!kpi) return;
    const { target: t, actual: a, note: n } = resolveMonth(kpi);
    setTarget(String(t ?? ""));
    setActual(String(a ?? "0"));
    setNote(n ?? "");
    setError("");
  }, [kpi]);

  const save = useMutation({
    mutationFn: () =>
      apiSend(`/api/kpis/${kpi!.id}/monthly`, "POST", {
        year,
        month,
        targetValue: target === "" ? null : Number(target),
        actualValue: actual === "" ? 0 : Number(actual),
        note: note.trim() || null,
      }),
    onSuccess: () => {
      onSaved();
      onClose();
    },
    onError: (e) => setError(e instanceof Error ? e.message : "Failed to save"),
  });

  if (!kpi) return null;
  return (
    <Dialog open={open} onClose={onClose} className="max-w-md">
      <DialogHeader title={`${MONTHS[month - 1]} ${year} — ${kpi.name}`} onClose={onClose} />
      <DialogBody>
        <p className="text-xs text-muted-foreground">
          Set this KPI&apos;s target and actual for {MONTHS[month - 1]} {year}. Other months
          are unaffected.
        </p>
        <div className="grid grid-cols-2 gap-3">
          <div className="space-y-1.5">
            <Label>Target ({kpi.unit})</Label>
            <Input
              type="number"
              step="any"
              value={target}
              onChange={(e) => setTarget(e.target.value)}
              placeholder={String(kpi.targetValue)}
              autoFocus
            />
          </div>
          <div className="space-y-1.5">
            <Label>Actual ({kpi.unit})</Label>
            <Input
              type="number"
              step="any"
              value={actual}
              onChange={(e) => setActual(e.target.value)}
            />
          </div>
        </div>
        <div className="space-y-1.5">
          <Label>Remarks / notes</Label>
          <Textarea
            value={note}
            onChange={(e) => setNote(e.target.value)}
            placeholder="Explain the result — e.g. why it was below target, what was done…"
          />
          <p className="text-[11px] text-muted-foreground">
            Helps management understand off-target months at a glance.
          </p>
        </div>
        {error && <p className="text-sm text-destructive">{error}</p>}
      </DialogBody>
      <DialogFooter>
        <Button type="button" variant="secondary" onClick={onClose}>
          Cancel
        </Button>
        <Button type="button" disabled={save.isPending} onClick={() => save.mutate()}>
          Save {MONTHS[month - 1]}
        </Button>
      </DialogFooter>
    </Dialog>
  );
}

// Inline manager for marketing channels — add, rename, activate, delete.
function ChannelsDialog({
  open,
  onClose,
  channels,
}: {
  open: boolean;
  onClose: () => void;
  channels: ChannelDTO[];
}) {
  const qc = useQueryClient();
  const [name, setName] = React.useState("");
  const [error, setError] = React.useState("");
  const [editingId, setEditingId] = React.useState<string | null>(null);
  const [editName, setEditName] = React.useState("");

  const refresh = () => qc.invalidateQueries({ queryKey: ["channels"] });

  const create = useMutation({
    mutationFn: () => apiSend("/api/channels", "POST", { name }),
    onSuccess: () => {
      setName("");
      setError("");
      refresh();
    },
    onError: (e) => setError(e instanceof Error ? e.message : "Failed to add"),
  });
  const rename = useMutation({
    mutationFn: (vars: { id: string; name: string }) =>
      apiSend(`/api/channels/${vars.id}`, "PATCH", { name: vars.name }),
    onSuccess: () => {
      setEditingId(null);
      setError("");
      refresh();
    },
    onError: (e) => setError(e instanceof Error ? e.message : "Failed to rename"),
  });
  const toggle = useMutation({
    mutationFn: (c: ChannelDTO) => apiSend(`/api/channels/${c.id}`, "PATCH", { active: !c.active }),
    onSuccess: refresh,
  });
  const remove = useMutation({
    mutationFn: (id: string) => apiSend(`/api/channels/${id}`, "DELETE"),
    onSuccess: refresh,
  });

  return (
    <Dialog open={open} onClose={onClose}>
      <DialogHeader title="Marketing channels" onClose={onClose} />
      <DialogBody>
        <p className="text-xs text-muted-foreground">
          Channels that KPIs can be attributed to (multi-select).
        </p>
        <div className="flex gap-2">
          <Input
            value={name}
            onChange={(e) => setName(e.target.value)}
            placeholder="e.g. Meta, Google, TikTok"
            onKeyDown={(e) => {
              if (e.key === "Enter" && name.trim()) {
                e.preventDefault();
                create.mutate();
              }
            }}
          />
          <Button type="button" onClick={() => name.trim() && create.mutate()} disabled={create.isPending}>
            <Plus className="size-4" /> Add
          </Button>
        </div>
        {error && <p className="text-sm text-destructive">{error}</p>}
        <div className="space-y-1.5">
          {channels.length === 0 ? (
            <EmptyState title="No channels yet" />
          ) : (
            channels.map((c) =>
              editingId === c.id ? (
                <div
                  key={c.id}
                  className="flex items-center gap-2 rounded-md border border-primary px-3 py-2"
                >
                  <Input
                    value={editName}
                    onChange={(e) => setEditName(e.target.value)}
                    autoFocus
                    onKeyDown={(e) => {
                      if (e.key === "Enter" && editName.trim())
                        rename.mutate({ id: c.id, name: editName.trim() });
                      if (e.key === "Escape") setEditingId(null);
                    }}
                  />
                  <Button
                    type="button"
                    size="sm"
                    disabled={!editName.trim() || rename.isPending}
                    onClick={() => rename.mutate({ id: c.id, name: editName.trim() })}
                  >
                    Save
                  </Button>
                  <Button type="button" variant="ghost" size="sm" onClick={() => setEditingId(null)}>
                    Cancel
                  </Button>
                </div>
              ) : (
                <div
                  key={c.id}
                  className="flex items-center justify-between rounded-md border border-border px-3 py-2"
                >
                  <div className="flex items-center gap-2">
                    <span className="text-sm font-medium">{c.name}</span>
                    {!c.active && <Badge variant="outline">Inactive</Badge>}
                  </div>
                  <div className="flex gap-1">
                    <Button
                      variant="ghost"
                      size="icon"
                      onClick={() => {
                        setEditingId(c.id);
                        setEditName(c.name);
                        setError("");
                      }}
                      title="Rename"
                    >
                      <Pencil className="size-3.5" />
                    </Button>
                    <Button variant="ghost" size="sm" onClick={() => toggle.mutate(c)}>
                      {c.active ? "Deactivate" : "Activate"}
                    </Button>
                    <Button variant="ghost" size="icon" onClick={() => remove.mutate(c.id)} title="Delete">
                      <Trash2 className="size-3.5" />
                    </Button>
                  </div>
                </div>
              )
            )
          )}
        </div>
      </DialogBody>
      <DialogFooter>
        <Button type="button" variant="secondary" onClick={onClose}>
          Done
        </Button>
      </DialogFooter>
    </Dialog>
  );
}

function initForm(kpi: KpiDTO | null) {
  return {
    name: kpi?.name ?? "",
    description: kpi?.description ?? "",
    type: (kpi?.type ?? "DEPARTMENT") as string,
    category: (kpi?.category ?? "OTHER") as string,
    targetValue: String(kpi?.targetValue ?? ""),
    unit: kpi?.unit ?? "",
    period: (kpi?.period ?? "MONTHLY") as string,
    companyId: kpi?.companyId ?? "",
    departmentId: kpi?.departmentId ?? "",
    assignedUserId: kpi?.assignedUserId ?? "",
    channelIds: kpi?.channels?.map((c) => c.id) ?? ([] as string[]),
    weightage: String(kpi?.weightage ?? "0"),
  };
}
