/**
 * Tính KPI tháng cho từng NVKD (yêu cầu cuối mục 3).
 *
 * Kết quả ghi vào `kpi_monthly` và là đầu vào cho cảnh báo "NVKD dưới 70%
 * hai tháng liên tiếp" ở M6.
 */
import { and, eq, gte, lte, sql, inArray } from "drizzle-orm";
import { db } from "@/db";
import {
  orders,
  users,
  customers,
  targets,
  kpiMonthly,
  checkIns,
  planItems,
  weeklyPlans,
} from "@/db/schema";
import { periodRange } from "./period";
import { isSpecialist, specialistDepartmentIds } from "./specialist";
import { vnDate } from "./sql-dates";

export async function recomputeKpi(tenantId: string, periodKey: string): Promise<number> {
  const { start, end } = periodRange(periodKey);

  // Nhân viên chuyên môn không bán hàng và không có chỉ tiêu doanh thu (KPI của họ là lớp đã dạy / KPI tự tạo):
  // đưa vào đây sẽ cho ra dòng 0% vô nghĩa và cảnh báo "không đạt chỉ tiêu" sai.
  const specialistDepartments = await specialistDepartmentIds(tenantId);
  const salesUsers = (
    await db
      .select({ id: users.id, jobTitle: users.jobTitle, departmentId: users.departmentId })
      .from(users)
      .where(
        and(eq(users.tenantId, tenantId), eq(users.isActive, true), inArray(users.role, ["SALES", "MANAGER"])),
      )
  ).filter((u) => !isSpecialist(u, specialistDepartments));

  if (salesUsers.length === 0) return 0;
  const userIds = salesUsers.map((u) => u.id);

  const orderStats = await db
    .select({
      userId: orders.salesUserId,
      revenue: sql<number>`coalesce(sum(${orders.totalAmount}), 0)::bigint`,
      orderCount: sql<number>`count(*)::int`,
      dealerCount: sql<number>`count(distinct ${orders.customerId})::int`,
    })
    .from(orders)
    .where(
      and(
        eq(orders.tenantId, tenantId),
        eq(orders.status, "CONFIRMED"),
        gte(orders.orderDate, start),
        lte(orders.orderDate, end),
      ),
    )
    .groupBy(orders.salesUserId);

  const visitStats = await db
    .select({
      userId: checkIns.userId,
      visitCount: sql<number>`count(distinct (${checkIns.customerId}, ${vnDate(checkIns.checkedAt)}))::int`,
    })
    .from(checkIns)
    .where(
      and(
        eq(checkIns.tenantId, tenantId),
        gte(vnDate(checkIns.checkedAt), start),
        lte(vnDate(checkIns.checkedAt), end),
      ),
    )
    .groupBy(checkIns.userId);

  const planStats = await db
    .select({
      userId: weeklyPlans.userId,
      total: sql<number>`count(*)::int`,
      done: sql<number>`count(*) filter (where ${planItems.status} = 'DONE')::int`,
    })
    .from(planItems)
    .innerJoin(weeklyPlans, eq(planItems.planId, weeklyPlans.id))
    .where(
      and(
        eq(planItems.tenantId, tenantId),
        gte(planItems.planDate, start),
        lte(planItems.planDate, end),
      ),
    )
    .groupBy(weeklyPlans.userId);

  const newCustomerStats = await db
    .select({
      ownerId: customers.ownerId,
      count: sql<number>`count(*)::int`,
    })
    .from(customers)
    .where(
      and(
        eq(customers.tenantId, tenantId),
        gte(vnDate(customers.createdAt), start),
        lte(vnDate(customers.createdAt), end),
      ),
    )
    .groupBy(customers.ownerId);

  const targetRows = await db
    .select({ scopeId: targets.scopeId, revenueTarget: targets.revenueTarget })
    .from(targets)
    .where(
      and(
        eq(targets.tenantId, tenantId),
        eq(targets.periodKey, periodKey),
        eq(targets.scopeType, "USER"),
      ),
    );

  const orderMap = new Map(orderStats.filter((r) => r.userId).map((r) => [r.userId!, r]));
  const visitMap = new Map(visitStats.map((r) => [r.userId, Number(r.visitCount)]));
  const planMap = new Map(planStats.map((r) => [r.userId, r]));
  const newCustomerMap = new Map(
    newCustomerStats.filter((r) => r.ownerId).map((r) => [r.ownerId!, Number(r.count)]),
  );
  const targetMap = new Map(
    targetRows.filter((r) => r.scopeId).map((r) => [r.scopeId!, Number(r.revenueTarget)]),
  );

  const rows = userIds.map((userId) => {
    const orderRow = orderMap.get(userId);
    const planRow = planMap.get(userId);
    const revenue = Number(orderRow?.revenue ?? 0);
    const revenueTarget = targetMap.get(userId) ?? 0;
    const planTotal = Number(planRow?.total ?? 0);

    return {
      tenantId,
      userId,
      periodKey,
      revenue,
      revenueTarget,
      achievementPct: revenueTarget > 0 ? Math.round((revenue / revenueTarget) * 100) : 0,
      orderCount: Number(orderRow?.orderCount ?? 0),
      visitCount: visitMap.get(userId) ?? 0,
      planCompliancePct: planTotal > 0 ? Math.round((Number(planRow!.done) / planTotal) * 100) : 0,
      newCustomerCount: newCustomerMap.get(userId) ?? 0,
      activeDealerCount: Number(orderRow?.dealerCount ?? 0),
      computedAt: new Date(),
    };
  });

  await db
    .delete(kpiMonthly)
    .where(and(eq(kpiMonthly.tenantId, tenantId), eq(kpiMonthly.periodKey, periodKey)));

  await db.insert(kpiMonthly).values(rows);
  return rows.length;
}
