import Link from "next/link";
import { and, asc, eq, ilike, inArray, or, sql, type SQL } from "drizzle-orm";
import { requireSession } from "@/lib/auth";
import { db } from "@/db";
import { users, departments, territories, userTerritories } from "@/db/schema";
import { canViewAllStaff, departmentPaths, departmentSubtree, expandTerritoryDescendants, visibleUserIds } from "@/lib/rbac";
import { formatDate, formatNumber, ROLE_LABEL } from "@/lib/format";
import { isUuid } from "@/lib/route-params";
import { staffAlerts } from "@/lib/staff-report";
import { specialistCondition, specialistDepartmentIds } from "@/lib/specialist";
import { lastCompletedMonth, today } from "@/lib/period";
import { PageHeader, TableWrap, EmptyState, Badge } from "@/components/ui";
import { Avatar } from "@/components/avatar";

export const dynamic = "force-dynamic";

const PAGE_SIZE = 50;

const TABS = [
  { key: "tat-ca", label: "Tất cả" },
  { key: "kinh-doanh", label: "Kinh doanh" },
  { key: "chuyen-mon", label: "Chuyên môn" },
] as const;
type TabKey = (typeof TABS)[number]["key"];

const NIL = "00000000-0000-0000-0000-000000000000";

/** Còn mấy ngày tới sinh nhật (0 = hôm nay); null nếu chưa có ngày sinh. */
function daysToBirthday(birthDate: string | null, todayIso: string): number | null {
  if (!birthDate) return null;
  const [, m, d] = birthDate.split("-").map(Number);
  const [year] = todayIso.split("-").map(Number);
  const base = Date.parse(`${todayIso}T00:00:00Z`);
  for (const y of [year, year + 1]) {
    // 29/02 ở năm không nhuận lùi về 28/02.
    const date = new Date(Date.UTC(y, m - 1, d));
    if (date.getUTCMonth() !== m - 1) date.setUTCDate(0);
    const diff = Math.round((date.getTime() - base) / 86_400_000);
    if (diff >= 0) return diff;
  }
  return null;
}

export default async function StaffListPage({ searchParams }: { searchParams: Promise<Record<string, string | undefined>> }) {
  const session = await requireSession();
  const params = await searchParams;

  const [me] = await db.select({ canEditStaffInfo: users.canEditStaffInfo }).from(users).where(eq(users.id, session.userId)).limit(1);
  // Hành chính nhân sự (được cấp quyền sửa thông tin nhân viên) xem được toàn bộ danh sách.
  const seesEveryone = session.role === "DIRECTOR" || !!me?.canEditStaffInfo;

  if (!canViewAllStaff(session) && !seesEveryone) {
    return (
      <>
        <PageHeader title="Nhân viên" />
        <EmptyState message="Bạn không có quyền xem danh sách nhân viên." hint="Dành cho Ban giám đốc, Giám đốc khu vực và Quản lý." />
      </>
    );
  }

  // Tham số lọc gõ trên đường dẫn: chỉ nhận đúng định dạng (uuid / giá trị cố định), giá trị lạ bỏ qua.
  const tab: TabKey = TABS.some((t) => t.key === params.tab) ? (params.tab as TabKey) : "tat-ca";
  const q = (params.q ?? "").trim().slice(0, 100);
  const kv = isUuid(params.kv) ? params.kv : "";
  const pb = isUuid(params.pb) ? params.pb : "";
  // Tab Chuyên môn không có cảnh báo (cảnh báo tính trên chỉ tiêu doanh thu kinh doanh): ẩn cột/ô lọc và bỏ qua tham số.
  const showAlerts = tab !== "chuyen-mon";
  const cb = showAlerts && (params.cb === "1" || params.cb === "nghiem-trong") ? params.cb : "";
  const pageParam = Number(params.trang);
  const wantedPage = Number.isInteger(pageParam) && pageParam >= 1 && pageParam <= 10_000 ? pageParam : 1;

  // Phạm vi: quản lý khu vực thấy mọi nhân viên trong nhánh của mình, quản lý phòng thấy nhân viên phòng mình (Ban giám đốc / HCNS: tất cả).
  const visibleIds = seesEveryone ? null : await visibleUserIds(session);
  const scope: SQL[] = [eq(users.tenantId, session.tenantId), eq(users.isActive, true)];
  if (visibleIds) scope.push(inArray(users.id, visibleIds.length > 0 ? visibleIds : [NIL]));

  // Nguồn cho các ô lọc: CHỈ phòng ban / khu vực của những nhân viên trong phạm vi người xem (không lộ cơ cấu ngoài nhánh).
  const [scopeRows, assignedRows, paths] = await Promise.all([
    db.select({ id: users.id, departmentId: users.departmentId, territoryId: users.territoryId }).from(users).where(and(...scope)),
    db.select({ userId: userTerritories.userId, territoryId: userTerritories.territoryId }).from(userTerritories).where(eq(userTerritories.tenantId, session.tenantId)),
    departmentPaths(session.tenantId),
  ]);
  const scopeIds = new Set(scopeRows.map((r) => r.id));
  const deptIds = new Set(scopeRows.map((r) => r.departmentId).filter((v): v is string => !!v));
  const territoryIds = new Set<string>();
  for (const row of scopeRows) if (row.territoryId) territoryIds.add(row.territoryId);
  for (const row of assignedRows) if (scopeIds.has(row.userId)) territoryIds.add(row.territoryId);
  const [departmentOptions, territoryOptions] = await Promise.all([
    deptIds.size > 0
      ? db
          .select({ id: departments.id, name: departments.name })
          .from(departments)
          .where(and(eq(departments.tenantId, session.tenantId), eq(departments.isActive, true), inArray(departments.id, [...deptIds])))
          .orderBy(asc(departments.sortOrder), asc(departments.code))
      : Promise.resolve([]),
    territoryIds.size > 0
      ? db
          .select({ id: territories.id, name: territories.name })
          .from(territories)
          .where(and(eq(territories.tenantId, session.tenantId), eq(territories.isActive, true), inArray(territories.id, [...territoryIds])))
          .orderBy(asc(territories.code))
      : Promise.resolve([]),
  ]);

  const filters: SQL[] = [...scope];
  if (q) {
    const term = `%${q}%`;
    filters.push(or(ilike(users.fullName, term), ilike(users.phone, term), ilike(users.email, term), ilike(users.jobTitle, term))!);
  }
  if (pb) {
    const subtree = await departmentSubtree(session.tenantId, [pb]);
    filters.push(inArray(users.departmentId, subtree.length > 0 ? subtree : [NIL]));
  }
  if (kv) {
    const area = await expandTerritoryDescendants(session.tenantId, [kv]);
    // Nhân viên thuộc khu vực đó, hoặc quản lý được giao phụ trách khu vực đó.
    filters.push(
      or(
        inArray(users.territoryId, area.length > 0 ? area : [NIL]),
        sql`users.id in (select user_id from user_territories where territory_id in (${sql.join((area.length > 0 ? area : [NIL]).map((id) => sql`${id}`), sql`, `)}))`,
      )!,
    );
  }
  if (cb) {
    // Cảnh báo đang hiệu lực = kỳ đã đóng sổ gần nhất (cảnh báo các kỳ cũ không tự đóng nên không tính).
    const severity = cb === "nghiem-trong" ? sql` and a.severity = 'CRITICAL'` : sql``;
    filters.push(
      sql`exists (select 1 from alerts a where a.tenant_id = ${session.tenantId} and a.entity_type = 'user' and a.entity_id = users.id and a.status = 'OPEN' and a.period_key = ${lastCompletedMonth()}${severity})`,
    );
  }

  // "Chuyên môn" = chức vụ chuyên môn hoặc thuộc phòng ban chuyên môn (xem src/lib/specialist.ts) — không tính người chỉ từng mở vài chuyên đề.
  const cmDepartmentIds = await specialistDepartmentIds(session.tenantId);
  const specialist = specialistCondition(cmDepartmentIds);
  const tabCondition = (key: TabKey): SQL | undefined => (key === "chuyen-mon" ? specialist : key === "kinh-doanh" ? sql`not ${specialist}` : undefined);
  const countFor = async (key: TabKey) => {
    const [row] = await db
      .select({ n: sql<number>`count(*)::int` })
      .from(users)
      .where(and(...filters, tabCondition(key)));
    return Number(row?.n ?? 0);
  };
  const [countAll, countSales, countSpecialist] = await Promise.all([countFor("tat-ca"), countFor("kinh-doanh"), countFor("chuyen-mon")]);
  const total = tab === "tat-ca" ? countAll : tab === "kinh-doanh" ? countSales : countSpecialist;
  const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE));
  const page = Math.min(wantedPage, totalPages);

  const rows = await db
    .select({
      id: users.id,
      fullName: users.fullName,
      email: users.email,
      phone: users.phone,
      jobTitle: users.jobTitle,
      role: users.role,
      birthDate: users.birthDate,
      avatar: users.avatarDataUrl,
      departmentId: users.departmentId,
      departmentName: departments.name,
      territoryName: territories.name,
    })
    .from(users)
    .leftJoin(departments, eq(users.departmentId, departments.id))
    .leftJoin(territories, eq(users.territoryId, territories.id))
    .where(and(...filters, tabCondition(tab)))
    .orderBy(asc(users.fullName))
    .limit(PAGE_SIZE)
    .offset((page - 1) * PAGE_SIZE);

  const alertsByUser = await staffAlerts(session.tenantId, rows.map((r) => r.id));
  const todayIso = today();

  const queryString = (patch: Record<string, string | number> = {}) => {
    const next: Record<string, string | number> = { tab, q, kv, pb, cb, trang: 1, ...patch };
    const qs = new URLSearchParams();
    for (const [key, value] of Object.entries(next)) {
      if (value === "" || (key === "tab" && value === "tat-ca") || (key === "trang" && value === 1)) continue;
      qs.set(key, String(value));
    }
    return qs.toString();
  };
  const href = (patch: Record<string, string | number> = {}) => {
    const text = queryString(patch);
    return text ? `/danh-muc/nhan-vien?${text}` : "/danh-muc/nhan-vien";
  };
  const tabCounts: Record<TabKey, number> = { "tat-ca": countAll, "kinh-doanh": countSales, "chuyen-mon": countSpecialist };

  const alertBadge = (userId: string) => {
    const list = alertsByUser.get(userId) ?? [];
    if (list.length === 0) return <span className="text-ink-300">—</span>;
    const critical = list.some((a) => a.severity === "CRITICAL");
    return (
      <div className="flex flex-col items-start gap-1">
        <Badge tone={critical ? "red" : "gold"}>{list.length} cảnh báo</Badge>
        <span className="max-w-56 text-[11px] leading-snug text-ink-500">{list[0].title}</span>
      </div>
    );
  };
  const birthdayBadge = (birthDate: string | null) => {
    const days = daysToBirthday(birthDate, todayIso);
    if (days === null || days > 7) return null;
    return <Badge tone="gold">{days === 0 ? "Sinh nhật hôm nay" : `Sinh nhật sau ${days} ngày`}</Badge>;
  };

  return (
    <>
      <PageHeader
        title="Nhân viên"
        subtitle="Nhân viên trong phạm vi bạn phụ trách (giám đốc khu vực: cả nhánh; quản lý phòng: nhân viên trong phòng). Bấm vào tên để xem hồ sơ và báo cáo chi tiết."
        actions={
          <Link href="/danh-muc" className="btn-ghost">
            ← Danh mục
          </Link>
        }
      />

      <div className="mb-4 flex w-fit gap-1 rounded-lg border border-[var(--color-line)] bg-white p-1">
        {TABS.map((item) => (
          <Link
            key={item.key}
            href={href({ tab: item.key })}
            className={`rounded-md px-3 py-1.5 text-sm font-semibold ${tab === item.key ? "bg-brand-500 text-white" : "text-ink-500 hover:bg-ink-50"}`}
          >
            {item.label} <span className="tnum font-normal opacity-80">{formatNumber(tabCounts[item.key])}</span>
          </Link>
        ))}
      </div>

      <form className="mb-4 flex flex-wrap items-end gap-3" action="/danh-muc/nhan-vien">
        {tab !== "tat-ca" && <input type="hidden" name="tab" value={tab} />}
        <div className="min-w-48 flex-1">
          <label htmlFor="q" className="label-caps mb-1.5 block">
            Tìm kiếm
          </label>
          <input id="q" name="q" defaultValue={q} className="input" placeholder="Họ tên, điện thoại, email, chức vụ…" />
        </div>
        <div>
          <label htmlFor="kv" className="label-caps mb-1.5 block">
            Khu vực
          </label>
          <select id="kv" name="kv" defaultValue={kv} className="input">
            <option value="">Tất cả</option>
            {territoryOptions.map((t) => (
              <option key={t.id} value={t.id}>
                {t.name}
              </option>
            ))}
          </select>
        </div>
        <div>
          <label htmlFor="pb" className="label-caps mb-1.5 block">
            Phòng ban / Team
          </label>
          <select id="pb" name="pb" defaultValue={pb} className="input">
            <option value="">Tất cả</option>
            {departmentOptions.map((d) => (
              <option key={d.id} value={d.id}>
                {paths.get(d.id) ?? d.name}
              </option>
            ))}
          </select>
        </div>
        {showAlerts && (
          <div>
            <label htmlFor="cb" className="label-caps mb-1.5 block">
              Cảnh báo
            </label>
            <select id="cb" name="cb" defaultValue={cb} className="input">
              <option value="">Tất cả</option>
              <option value="1">Đang có cảnh báo</option>
              <option value="nghiem-trong">Cảnh báo nghiêm trọng</option>
            </select>
          </div>
        )}
        <button type="submit" className="btn-ghost">
          Lọc
        </button>
        {(q || kv || pb || cb) && (
          <Link href={href({ q: "", kv: "", pb: "", cb: "" })} className="pb-2 text-sm text-ink-500 hover:underline">
            Bỏ lọc
          </Link>
        )}
      </form>

      {rows.length === 0 ? (
        <EmptyState message="Không có nhân viên phù hợp bộ lọc." />
      ) : (
        <>
          {/* Điện thoại: mỗi người một thẻ. */}
          <div className="flex flex-col gap-2 md:hidden">
            {rows.map((row) => (
              <Link key={row.id} href={`/danh-muc/nguoi-dung/${row.id}`} className="card flex items-start gap-3 p-3.5 active:bg-ink-50">
                <Avatar name={row.fullName} src={row.avatar} size={40} />
                <div className="min-w-0 flex-1">
                  <div className="font-semibold text-ink-700">{row.fullName}</div>
                  <div className="text-[11px] text-ink-400">
                    {row.jobTitle ?? ROLE_LABEL[row.role]}
                    {row.departmentId ? ` · ${paths.get(row.departmentId) ?? row.departmentName ?? ""}` : ""}
                  </div>
                  <div className="mt-1 text-xs text-ink-500">
                    {row.phone ?? "—"}
                    {row.birthDate ? ` · sinh ${formatDate(row.birthDate)}` : ""}
                  </div>
                  <div className="mt-1.5 flex flex-wrap gap-1.5">
                    {birthdayBadge(row.birthDate)}
                    {showAlerts && (alertsByUser.get(row.id) ?? []).length > 0 && <Badge tone="red">{alertsByUser.get(row.id)!.length} cảnh báo</Badge>}
                  </div>
                </div>
              </Link>
            ))}
          </div>

          <div className="hidden md:block">
            <TableWrap>
              <thead>
                <tr>
                  <th>Họ tên</th>
                  <th>Phòng ban</th>
                  <th>Chức vụ</th>
                  <th>Khu vực</th>
                  <th>Điện thoại</th>
                  <th>Ngày sinh</th>
                  {showAlerts && <th>Cảnh báo</th>}
                </tr>
              </thead>
              <tbody>
                {rows.map((row) => (
                  <tr key={row.id} className="align-top">
                    <td>
                      <Link href={`/danh-muc/nguoi-dung/${row.id}`} className="flex items-center gap-2.5 font-medium text-ink-700 hover:text-brand-600">
                        <Avatar name={row.fullName} src={row.avatar} size={32} />
                        <span>
                          {row.fullName}
                          {/* Vai trò hệ thống (quyền hạn) chỉ hiện ở tab có lẫn kinh doanh; nhân viên chuyên môn đã có cột Chức vụ. */}
                          {tab !== "chuyen-mon" && <span className="block text-[11px] font-normal text-ink-400">{ROLE_LABEL[row.role]}</span>}
                        </span>
                      </Link>
                    </td>
                    <td className="text-ink-500">{row.departmentId ? (paths.get(row.departmentId) ?? row.departmentName) : "—"}</td>
                    <td className="text-ink-500">{row.jobTitle ?? "—"}</td>
                    <td className="text-ink-500">{row.territoryName ?? "—"}</td>
                    <td className="tnum whitespace-nowrap text-ink-500">{row.phone ?? "—"}</td>
                    <td className="tnum text-ink-500">
                      {row.birthDate ? formatDate(row.birthDate) : "—"}
                      <div className="mt-0.5">{birthdayBadge(row.birthDate)}</div>
                    </td>
                    {showAlerts && <td>{alertBadge(row.id)}</td>}
                  </tr>
                ))}
              </tbody>
            </TableWrap>
          </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: 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(total)} nhân viên
          </span>
          {page < totalPages ? (
            <Link href={href({ trang: page + 1 })} className="btn-ghost">
              Sau →
            </Link>
          ) : (
            <span className="btn-ghost pointer-events-none opacity-40">Sau →</span>
          )}
        </nav>
      )}
      <p className="mt-3 text-xs text-ink-400">
        “Chuyên môn” gồm nhân viên có chức vụ chuyên môn hoặc thuộc phòng ban chuyên môn (mở lớp/chuyên đề đơn lẻ không làm một nhân viên kinh doanh thành chuyên môn).
        {showAlerts &&
          " Cảnh báo lấy từ kỳ đã đóng sổ gần nhất của hệ thống quét hằng đêm (ví dụ không đạt chỉ tiêu hai tháng liên tiếp); cảnh báo của kỳ cũ hơn không tính."}
      </p>
    </>
  );
}
