import Link from "next/link";
import { and, count, desc, eq, inArray } from "drizzle-orm";
import { requireSession } from "@/lib/auth";
import { canEditCatalog, canViewAllStaff } from "@/lib/rbac";
import { alertScope } from "@/lib/alerts-scope";
import { db } from "@/db";
import { alerts } from "@/db/schema";
import { forecastTable } from "@/lib/forecast";
import { lastCompletedMonth, shiftMonth, today, monthKey } from "@/lib/period";
import { ALERT_TYPE_LABEL, formatDateTime, formatNumber, formatPercent, formatPeriod, PRODUCT_ROLE_LABEL } from "@/lib/format";
import { ActionForm } from "@/components/action-form";
import { Badge, EmptyState, PageHeader, SectionTitle, StatCard, TableWrap } from "@/components/ui";
import { acknowledgeAlertAction, adjustForecastAction } from "./actions";

export const dynamic = "force-dynamic";

const SEVERITY_LABEL = { CRITICAL: "Nghiêm trọng", WARNING: "Cảnh báo", INFO: "Lưu ý" } as const;
type Severity = keyof typeof SEVERITY_LABEL;

/** 5 nhóm cảnh báo theo yêu cầu của khách. Dự báo là mục riêng (`muc=du-bao`). */
const GROUPS = [
  { key: "dai-ly", label: "Đại lý", hint: "không lấy hàng ≥ 2 tháng, doanh thu giảm", types: ["DEALER_INACTIVE", "DEALER_REVENUE_DROP"] },
  { key: "san-pham", label: "Sản phẩm", hint: "không có doanh thu, sản lượng giảm", types: ["PRODUCT_NO_REVENUE", "PRODUCT_VOLUME_DROP"] },
  { key: "thi-truong", label: "Thị trường", hint: "không có doanh thu, tụt giảm", types: ["TERRITORY_NO_REVENUE", "TERRITORY_REVENUE_DROP"] },
  { key: "nhan-su", label: "Nhân sự", hint: "không đạt chỉ tiêu 2 tháng liên tiếp", types: ["STAFF_UNDERPERFORM"] },
] as const;

const STATUSES = [
  { key: "chua-xu-ly", label: "Chưa xử lý", db: "OPEN" },
  { key: "da-xu-ly", label: "Đã xử lý", db: "ACKNOWLEDGED" },
  { key: "het-hieu-luc", label: "Hết hiệu lực", db: "RESOLVED" },
] as const;

const PAGE_SIZE = 50;

/** Trang chi tiết của đối tượng bị cảnh báo. */
function entityLink(alert: { entityType: string; entityId: string | null; periodKey: string }): { href: string; label: string } | null {
  if (!alert.entityId) return null;
  switch (alert.entityType) {
    case "customer":
      return { href: `/khach-hang/${alert.entityId}`, label: "Xem khách hàng" };
    case "user":
      return { href: `/danh-muc/nguoi-dung/${alert.entityId}?ky=thang&ngay=${alert.periodKey}-15`, label: "Xem nhân viên" };
    case "territory":
      return { href: `/phan-tich?muc=ty-trong&dv=khu-vuc&ky=${alert.periodKey}&pv=terr:${alert.entityId}`, label: "Xem thị trường" };
    case "product":
      return { href: `/phan-tich?muc=san-pham&ky=${alert.periodKey}`, label: "Xem sản phẩm" };
    default:
      return null;
  }
}

export default async function AlertsPage({
  searchParams,
}: {
  searchParams: Promise<{ trangthai?: string; nhom?: string; md?: string; muc?: string; ky?: string; trang?: string }>;
}) {
  const session = await requireSession();

  if (!canViewAllStaff(session)) {
    return (
      <>
        <PageHeader title="Cảnh báo" />
        <EmptyState message="Bạn không có quyền xem cảnh báo." hint="Chức năng này dành cho Ban giám đốc, Giám đốc khu vực và Quản lý." />
      </>
    );
  }

  const params = await searchParams;
  const section = params.muc === "du-bao" ? "du-bao" : "canh-bao";
  const status = STATUSES.find((s) => s.key === params.trangthai) ?? STATUSES[0];
  const group = GROUPS.find((g) => g.key === params.nhom);
  const severity: Severity | "" = (["CRITICAL", "WARNING", "INFO"] as const).find((s) => s === params.md) ?? "";
  const pageParam = Number(params.trang);
  const wantedPage = Number.isInteger(pageParam) && pageParam >= 1 && pageParam <= 10_000 ? pageParam : 1;

  const href = (patch: Record<string, string> = {}) => {
    const next: Record<string, string> = { muc: section === "du-bao" ? "du-bao" : "", trangthai: status.key === "chua-xu-ly" ? "" : status.key, nhom: group?.key ?? "", md: severity, ...patch };
    const qs = new URLSearchParams();
    for (const [key, value] of Object.entries(next)) if (value) qs.set(key, value);
    const text = qs.toString();
    return text ? `/canh-bao?${text}` : "/canh-bao";
  };

  const header = (
    <PageHeader
      title="Cảnh báo & dự báo"
      subtitle="Hệ thống tự quét mỗi đêm: đại lý ngừng lấy hàng hoặc giảm doanh thu, sản phẩm không có doanh thu hoặc giảm sản lượng, thị trường không có doanh thu hoặc tụt giảm, nhân sự không đạt chỉ tiêu 2 tháng liên tiếp — kèm dự báo dự trù sản phẩm các tháng tới."
    />
  );
  const sectionTabs = (
    <div className="mb-5 flex w-fit gap-1 rounded-lg border border-[var(--color-line)] bg-white p-1">
      <Link href="/canh-bao" className={`rounded-md px-3 py-1.5 text-sm font-semibold ${section === "canh-bao" ? "bg-brand-500 text-white" : "text-ink-500 hover:bg-ink-50"}`}>
        Cảnh báo
      </Link>
      <Link href="/canh-bao?muc=du-bao" className={`rounded-md px-3 py-1.5 text-sm font-semibold ${section === "du-bao" ? "bg-brand-500 text-white" : "text-ink-500 hover:bg-ink-50"}`}>
        Dự báo dự trù
      </Link>
    </div>
  );

  /* ------------------------------ Dự báo dự trù ------------------------------ */
  if (section === "du-bao") {
    const months = Array.from({ length: 3 }, (_, i) => shiftMonth(monthKey(today()), -(i + 1)));
    const period = months.find((m) => m === params.ky) ?? months[0];
    const rows = await forecastTable(session.tenantId, period, lastCompletedMonth());
    const canAdjust = canEditCatalog(session);
    const total = rows.reduce((sum, r) => sum + r.planQty, 0);
    const adjusted = rows.filter((r) => r.adjustedQty != null).length;
    const computedAt = rows.reduce<Date | null>((latest, r) => (!latest || r.computedAt > latest ? r.computedAt : latest), null);

    return (
      <>
        {header}
        {sectionTabs}
        <div className="mb-4 flex flex-wrap items-center gap-1.5 text-sm">
          <span className="label-caps mr-1">Dự trù cho</span>
          {months.map((m) => (
            <Link key={m} href={`/canh-bao?muc=du-bao&ky=${m}`} className={`rounded-full border px-3 py-1 font-semibold ${period === m ? "border-brand-500 bg-brand-500 text-white" : "border-[var(--color-line)] bg-white text-ink-500 hover:bg-ink-50"}`}>
              {formatPeriod(m)}
            </Link>
          ))}
          <a href={`/api/xuat-excel?loai=du-bao&ky=${period}`} className="btn-ghost ml-auto px-3 py-1.5 text-xs" download>
            Xuất Excel
          </a>
        </div>

        <div className="mb-4 grid grid-cols-2 gap-3 lg:grid-cols-4">
          <StatCard label="Sản phẩm được dự trù" value={formatNumber(rows.length)} hint={formatPeriod(period)} />
          <StatCard label="Tổng số lượng dự trù" value={formatNumber(total)} hint="số chỉnh tay nếu có, không thì số máy tính" />
          <StatCard label="Dòng đã chỉnh tay" value={formatNumber(adjusted)} hint={adjusted > 0 ? "giữ nguyên khi hệ thống tính lại hằng đêm" : "chưa chỉnh dòng nào"} />
          <StatCard label="Tính lần cuối" value={computedAt ? formatDateTime(computedAt).slice(0, 5) : "—"} hint={computedAt ? formatDateTime(computedAt) : "chưa có dự báo"} />
        </div>

        <TableWrap>
          <thead>
            <tr>
              <th>Mã</th>
              <th>Sản phẩm</th>
              <th>Nhóm</th>
              <th className="text-right">Bán {formatPeriod(lastCompletedMonth()).toLowerCase()}</th>
              <th className="text-right">Bình quân 3 tháng</th>
              <th className="text-right">Cùng kỳ năm trước</th>
              <th className="text-right">Dự báo (máy tính)</th>
              <th className="text-right">Điều chỉnh</th>
              <th className="text-right">Dự trù</th>
              <th className="text-right">Độ tin cậy</th>
            </tr>
          </thead>
          <tbody>
            {rows.length === 0 && (
              <tr>
                <td colSpan={10} className="py-8 text-center text-ink-400">
                  Chưa có dự báo cho {formatPeriod(period)}. Hệ thống tính lại mỗi đêm (<code>npm run jobs:nightly</code>).
                </td>
              </tr>
            )}
            {rows.map((row) => (
              <tr key={row.id}>
                <td className="tnum text-ink-400">{row.code}</td>
                <td className="min-w-48 font-medium text-ink-700">
                  {row.name}
                  {row.role === "CORE" && <span className="ml-1.5 text-[10px] font-semibold text-brand-600">{PRODUCT_ROLE_LABEL.CORE}</span>}
                </td>
                <td className="text-ink-500">{row.groupName}</td>
                <td className="tnum text-right text-ink-500">{formatNumber(row.lastMonthQty)}</td>
                <td className="tnum text-right text-ink-500">{formatNumber(row.avgQty)}</td>
                <td className="tnum text-right text-ink-400">{row.lastYearQty != null ? formatNumber(row.lastYearQty) : "—"}</td>
                <td className="tnum text-right text-ink-500">{formatNumber(row.forecastQty)}</td>
                <td className="text-right">
                  {canAdjust ? (
                    <ActionForm action={adjustForecastAction} className="flex items-center justify-end gap-1">
                      <input type="hidden" name="id" value={row.id} />
                      <input type="number" name="adjustedQty" min={0} max={10_000_000} defaultValue={row.adjustedQty ?? ""} placeholder={String(row.forecastQty)} aria-label={`Số lượng điều chỉnh cho ${row.name}`} className="input tnum w-24 py-1 text-right text-sm" />
                      <button type="submit" className="btn-ghost px-2 py-1 text-xs">
                        Lưu
                      </button>
                    </ActionForm>
                  ) : (
                    <span className="tnum text-ink-500">{row.adjustedQty != null ? formatNumber(row.adjustedQty) : "—"}</span>
                  )}
                </td>
                <td className="tnum text-right font-bold text-ink-700">{formatNumber(row.planQty)}</td>
                <td className="tnum text-right">
                  <Badge tone={(row.confidence ?? 0) >= 0.7 ? "green" : (row.confidence ?? 0) >= 0.4 ? "gold" : "red"}>{formatPercent((row.confidence ?? 0) * 100)}</Badge>
                </td>
              </tr>
            ))}
            {rows.length > 0 && (
              <tr className="border-t-2 border-[var(--color-line)] font-semibold">
                <td colSpan={8}>Tổng cộng</td>
                <td className="tnum text-right">{formatNumber(total)}</td>
                <td />
              </tr>
            )}
          </tbody>
        </TableWrap>
        <p className="mt-2 text-xs text-ink-400">
          Dự báo = bình quân 3 tháng đã đóng sổ gần nhất nhân hệ số mùa vụ của tháng đích (cùng tháng năm trước so với bình quân năm trước; chỉ áp khi năm trước có từ 6 tháng dữ liệu).
          Độ tin cậy thấp khi ít lịch sử hoặc sản lượng biến động mạnh. Quản lý chỉnh tay cột “Điều chỉnh” trước khi chốt đặt hàng; để trống thì dùng lại số máy tính. Số chỉnh tay không bị mất khi hệ thống tính lại.
        </p>
      </>
    );
  }

  /* ------------------------------ Danh sách cảnh báo ------------------------------ */
  const base = and(await alertScope(session), eq(alerts.status, status.db));
  const groupTypes = group ? [...group.types] : null;
  const filtered = and(base, groupTypes ? inArray(alerts.type, groupTypes) : undefined, severity ? eq(alerts.severity, severity) : undefined);

  const [typeCounts, [{ n: total }]] = await Promise.all([
    db.select({ type: alerts.type, severity: alerts.severity, n: count() }).from(alerts).where(base).groupBy(alerts.type, alerts.severity),
    db.select({ n: count() }).from(alerts).where(filtered),
  ]);
  const totalPages = Math.max(1, Math.ceil(Number(total) / PAGE_SIZE));
  const page = Math.min(wantedPage, totalPages);
  const rows = await db
    .select()
    .from(alerts)
    .where(filtered)
    .orderBy(desc(alerts.severity), desc(alerts.createdAt), alerts.title)
    .limit(PAGE_SIZE)
    .offset((page - 1) * PAGE_SIZE);

  const groupCount = (g: (typeof GROUPS)[number]) => typeCounts.filter((r) => (g.types as readonly string[]).includes(r.type)).reduce((sum, r) => sum + Number(r.n), 0);
  const inGroup = typeCounts.filter((r) => !groupTypes || groupTypes.includes(r.type));
  const bySeverity = (level: Severity) => inGroup.filter((r) => r.severity === level).reduce((sum, r) => sum + Number(r.n), 0);
  const allCount = typeCounts.reduce((sum, r) => sum + Number(r.n), 0);

  const chip = (active: boolean) => `rounded-full border px-3 py-1 text-sm font-semibold ${active ? "border-brand-500 bg-brand-500 text-white" : "border-[var(--color-line)] bg-white text-ink-500 hover:bg-ink-50"}`;

  return (
    <>
      {header}
      {sectionTabs}

      <div className="mb-4 flex flex-wrap items-center gap-1.5">
        {STATUSES.map((s) => (
          <Link key={s.key} href={href({ trangthai: s.key === "chua-xu-ly" ? "" : s.key, trang: "" })} className={`rounded-md border px-3 py-1 text-sm font-semibold ${status.key === s.key ? "border-ink-700 bg-ink-700 text-white" : "border-[var(--color-line)] bg-white text-ink-500 hover:bg-ink-50"}`}>
            {s.label}
          </Link>
        ))}
      </div>

      <div className="mb-4 flex flex-wrap items-center gap-1.5">
        <Link href={href({ nhom: "", trang: "" })} className={chip(!group)}>
          Tất cả <span className="tnum font-normal opacity-80">{allCount}</span>
        </Link>
        {GROUPS.map((g) => (
          <Link key={g.key} href={href({ nhom: g.key, trang: "" })} className={chip(group?.key === g.key)} title={g.hint}>
            {g.label} <span className="tnum font-normal opacity-80">{groupCount(g)}</span>
          </Link>
        ))}
      </div>

      {status.db === "OPEN" && (
        <div className="mb-5 grid grid-cols-3 gap-3">
          {(["CRITICAL", "WARNING", "INFO"] as const).map((level) => (
            <Link key={level} href={href({ md: severity === level ? "" : level, trang: "" })} className={severity === level ? "rounded-xl ring-2 ring-brand-500" : ""}>
              <StatCard label={SEVERITY_LABEL[level]} value={String(bySeverity(level))} tone={level === "CRITICAL" ? "bad" : level === "WARNING" ? "warn" : "default"} />
            </Link>
          ))}
        </div>
      )}

      {rows.length === 0 ? (
        <EmptyState
          message={status.db === "OPEN" ? "Không có cảnh báo nào cần xử lý." : status.db === "ACKNOWLEDGED" ? "Chưa có cảnh báo nào được đánh dấu đã xử lý." : "Không có cảnh báo hết hiệu lực."}
          hint={group || severity ? "Thử bỏ bớt bộ lọc." : "Bộ quét chạy trong job hằng đêm (npm run jobs:nightly)."}
        />
      ) : (
        <div className="flex flex-col gap-2">
          {rows.map((alert) => {
            const link = entityLink(alert);
            return (
              <div key={alert.id} className="card flex flex-wrap items-start gap-4 p-4">
                <span className={`mt-1.5 h-2.5 w-2.5 shrink-0 rounded-full ${alert.severity === "CRITICAL" ? "bg-red-500" : alert.severity === "WARNING" ? "bg-gold-500" : "bg-ink-300"}`} aria-hidden />
                <div className="min-w-56 flex-1">
                  <div className="flex flex-wrap items-center gap-2">
                    {alert.severity !== "INFO" && <span aria-hidden>⚠️</span>}
                    <span className="font-semibold text-ink-700">{alert.title}</span>
                    <Badge tone={alert.severity === "CRITICAL" ? "red" : alert.severity === "WARNING" ? "gold" : "neutral"}>{SEVERITY_LABEL[alert.severity]}</Badge>
                    <Badge>{ALERT_TYPE_LABEL[alert.type]}</Badge>
                  </div>
                  <p className="mt-1 text-sm text-ink-500">{alert.message}</p>
                  <p className="mt-1.5 text-[11px] text-ink-400">
                    Kỳ {formatPeriod(alert.periodKey)} · phát hiện {formatDateTime(alert.createdAt)}
                    {alert.acknowledgedAt ? ` · xử lý ${formatDateTime(alert.acknowledgedAt)}` : ""}
                    {link && (
                      <>
                        {" · "}
                        <Link href={link.href} className="text-brand-600 hover:underline">
                          {link.label}
                        </Link>
                      </>
                    )}
                  </p>
                </div>
                {alert.status === "OPEN" && (
                  <ActionForm action={acknowledgeAlertAction}>
                    <input type="hidden" name="id" value={alert.id} />
                    <button type="submit" className="btn-ghost text-xs">
                      Đánh dấu đã xử lý
                    </button>
                  </ActionForm>
                )}
              </div>
            );
          })}
        </div>
      )}

      {totalPages > 1 && (
        <nav className="mt-4 flex items-center justify-center gap-3 text-sm" aria-label="Phân trang">
          {page > 1 ? (
            <Link href={href({ trang: String(page - 1) })} className="btn-ghost">
              ← Trước
            </Link>
          ) : (
            <span className="btn-ghost pointer-events-none opacity-40">← Trước</span>
          )}
          <span className="text-ink-500">
            Trang {page}/{totalPages} · {formatNumber(Number(total))} cảnh báo
          </span>
          {page < totalPages ? (
            <Link href={href({ trang: String(page + 1) })} className="btn-ghost">
              Sau →
            </Link>
          ) : (
            <span className="btn-ghost pointer-events-none opacity-40">Sau →</span>
          )}
        </nav>
      )}

      <div className="mt-6">
        <SectionTitle>Cách hệ thống tính</SectionTitle>
        <ul className="list-disc pl-5 text-xs text-ink-400">
          <li>Quét mỗi đêm trên THÁNG ĐÃ ĐÓNG SỔ gần nhất; cảnh báo kỳ cũ tự chuyển “Hết hiệu lực” khi kỳ mới được đánh giá lại (còn vấn đề thì kỳ mới sinh cảnh báo mới).</li>
          <li>Đại lý: không lấy hàng từ 2 tháng (lưu ý), 3 tháng (cảnh báo), 6 tháng (nghiêm trọng); doanh thu giảm từ ngưỡng % so với tháng trước, quý trước (3 tháng so với 3 tháng liền trước), năm trước (12 tháng so với 12 tháng liền trước).</li>
          <li>Sản phẩm: không có doanh thu trong tháng dù đã từng bán trong 12 tháng gần nhất (nhắc lại mỗi tháng còn không bán); sản lượng giảm từ ngưỡng % theo ba mốc trên.</li>
          <li>Thị trường (tỉnh và miền): không có doanh thu; doanh thu giảm từ ngưỡng % theo ba mốc trên.</li>
          <li>Nhân sự: hoàn thành dưới ngưỡng % chỉ tiêu 2 tháng liên tiếp (chỉ người đã được giao chỉ tiêu). Ngưỡng sụt giảm và ngưỡng nhân sự do Ban giám đốc chỉnh ở Danh mục → Cài đặt.</li>
        </ul>
      </div>
    </>
  );
}

