import { cache } from "react";
import { and, asc, desc, eq, gte, inArray, lte, sql } from "drizzle-orm";
import {
  departments,
  employees,
  trainingPolicies,
  trainingRecords,
} from "@/db/schema";
import { getTrainingCategoryLabel } from "@/constants/thai-labels";
import { getDashboardAnnouncementsForAccess } from "@/features/announcements/server/announcement-data";
import {
  getPrimaryEmployeeIdForUser,
  getEmployeeIdsForUser,
} from "@/features/employees/server/employee-identity-linking";
import {
  getResolvedTrainingTargetForEmployee,
  getResolvedTrainingTargetsForEmployees,
} from "@/features/training-policy/server/employee-training-target-data";
import { requireOrganizationAccess } from "@/lib/auth/session";
import { isOrganizationAdminRole } from "@/lib/auth/roles";
import { searchParamsCache } from "@/lib/searchparams";
import { db } from "@/lib/db";

const PIE_COLORS = [
  "var(--chart-1)",
  "var(--chart-2)",
  "var(--chart-3)",
  "var(--chart-4)",
  "var(--chart-5)",
] as const;

const employeeCompanyExpr = sql<string>`coalesce(${employees.company}, ${employees.companyName})`;

type SummaryCard = {
  title: string;
  value: string;
  badge: string;
  direction: "up" | "down" | "neutral";
  description: string;
  footer: string;
};

type OverviewScope = {
  organizationId: string;
  userId: string;
  role: string;
  businessRole: "IT" | "HRD" | "EMPLOYEE" | null;
  systemRole: string | null;
  permissions: readonly string[];
};

export type OverviewFilterOption = {
  value: string;
  label: string;
};

export type OverviewFilters = {
  year: number;
  company: string | null;
  departmentId: number | null;
};

export type OverviewProgressItem = {
  key: "K" | "S" | "A";
  label: string;
  approvedHours: number;
  targetHours: number;
  percent: number;
  remainingHours: number;
};

export type OverviewRecentActivityItem = {
  id: number;
  employeeName: string;
  employeeCode: string | null;
  courseName: string;
  status: "draft" | "pending" | "approved" | "rejected" | "needs_revision";
  trainingDate: string;
  initials: string;
};

export type OverviewAnnouncementItem = {
  id: number;
  title: string;
  content: string;
  isPin: boolean;
  createdAt: string;
  href: string;
};

export type OverviewMonthlyTrendPoint = {
  month: string;
  approvedHours: number;
  approvedRecords: number;
};

export type OverviewDistributionPoint = {
  label: string;
  value: number;
  fill: string;
};

export type OverviewRankingPoint = {
  label: string;
  value: number;
};

export type OverviewDashboardData = {
  role: string;
  businessRole: "IT" | "HRD" | "EMPLOYEE" | null;
  filters: OverviewFilters;
  options: {
    years: OverviewFilterOption[];
    companies: OverviewFilterOption[];
    departments: OverviewFilterOption[];
  };
  cards: SummaryCard[];
  employee: {
    ksaProgress: OverviewProgressItem[];
    recentActivity: OverviewRecentActivityItem[];
    announcements: OverviewAnnouncementItem[];
  };
  hrd: {
    monthlyTrend: OverviewMonthlyTrendPoint[];
    ksaDistribution: OverviewDistributionPoint[];
    departmentRanking: OverviewRankingPoint[];
    topCourses: OverviewRankingPoint[];
  };
};

function formatNumber(value: number) {
  return new Intl.NumberFormat("th-TH", {
    minimumFractionDigits: value % 1 === 0 ? 0 : 1,
    maximumFractionDigits: 1,
  }).format(value);
}

function formatPercent(value: number) {
  return `${new Intl.NumberFormat("th-TH", {
    minimumFractionDigits: value % 1 === 0 ? 0 : 1,
    maximumFractionDigits: 1,
  }).format(value)}%`;
}

function getInitials(name: string) {
  return name
    .split(/\s+/)
    .filter(Boolean)
    .slice(0, 2)
    .map((part) => part[0]?.toUpperCase() ?? "")
    .join("");
}

function getMonthLabels(year: number) {
  return Array.from({ length: 12 }, (_, index) => {
    const date = new Date(Date.UTC(year, index, 1));
    return {
      monthNumber: index + 1,
      label: date.toLocaleDateString("th-TH", { month: "short" }),
    };
  });
}

function getYearRange(year: number) {
  return {
    start: new Date(Date.UTC(year, 0, 1)),
    end: new Date(Date.UTC(year + 1, 0, 1)),
  };
}

const getOverviewScope = cache(async (): Promise<OverviewScope> => {
  const { session, membership, organization } =
    await requireOrganizationAccess();

  return {
    organizationId: organization.id,
    userId: session.user.id,
    role: membership.role,
    businessRole: session.user.businessRole,
    systemRole: session.user.systemRole,
    permissions: session.user.effectivePermissions,
  };
});

const getOverviewFilters = cache(async (): Promise<OverviewFilters> => {
  const currentYear = new Date().getUTCFullYear();
  const rawYear = searchParamsCache.get("year");
  const rawDepartment = searchParamsCache.get("department");
  const year = rawYear ? Number(rawYear) : currentYear;
  const departmentId = rawDepartment ? Number(rawDepartment) : null;

  return {
    year: Number.isFinite(year) && year > 2000 ? year : currentYear,
    company: searchParamsCache.get("company")?.trim() || null,
    departmentId:
      departmentId !== null && Number.isFinite(departmentId)
        ? departmentId
        : null,
  };
});

async function getOverviewPolicy(organizationId: string, year: number) {
  const [policy] = await db
    .select({
      year: trainingPolicies.year,
      totalHours: trainingPolicies.totalHours,
      kHours: trainingPolicies.kHours,
      sHours: trainingPolicies.sHours,
      aHours: trainingPolicies.aHours,
    })
    .from(trainingPolicies)
    .where(
      and(
        eq(trainingPolicies.organizationId, organizationId),
        eq(trainingPolicies.year, year),
      ),
    )
    .orderBy(desc(trainingPolicies.updatedAt))
    .limit(1);

  if (policy) {
    return policy;
  }

  const [latestPolicy] = await db
    .select({
      year: trainingPolicies.year,
      totalHours: trainingPolicies.totalHours,
      kHours: trainingPolicies.kHours,
      sHours: trainingPolicies.sHours,
      aHours: trainingPolicies.aHours,
    })
    .from(trainingPolicies)
    .where(eq(trainingPolicies.organizationId, organizationId))
    .orderBy(desc(trainingPolicies.year), desc(trainingPolicies.updatedAt))
    .limit(1);

  return (
    latestPolicy ?? {
      year,
      totalHours: 0,
      kHours: 0,
      sHours: 0,
      aHours: 0,
    }
  );
}

const getOverviewFilterOptions = cache(
  async (): Promise<OverviewDashboardData["options"]> => {
    const scope = await getOverviewScope();
    const selfEmployeeIds = await getEmployeeIdsForUser({
      organizationId: scope.organizationId,
      userId: scope.userId,
    });
    const restrictToSelf = !isOrganizationAdminRole(scope.role);

    const [yearRows, companyRows, departmentRows] = await Promise.all([
      db
        .select({
          year: sql<number>`extract(year from ${trainingRecords.trainingDate})::int`,
        })
        .from(trainingRecords)
        .where(eq(trainingRecords.organizationId, scope.organizationId))
        .groupBy(sql`extract(year from ${trainingRecords.trainingDate})`)
        .orderBy(desc(sql`extract(year from ${trainingRecords.trainingDate})`)),
      db
        .select({
          company: employeeCompanyExpr,
        })
        .from(employees)
        .where(
          and(
            eq(employees.organizationId, scope.organizationId),
            eq(employees.isActive, true),
            ...(restrictToSelf && selfEmployeeIds.length > 0
              ? [inArray(employees.id, selfEmployeeIds)]
              : []),
            ...(restrictToSelf && selfEmployeeIds.length === 0
              ? [eq(employees.id, -1)]
              : []),
          ),
        )
        .groupBy(employeeCompanyExpr)
        .orderBy(asc(employeeCompanyExpr)),
      db
        .select({
          id: departments.id,
          name: departments.name,
        })
        .from(departments)
        .where(
          and(
            eq(departments.organizationId, scope.organizationId),
            eq(departments.isActive, true),
          ),
        )
        .orderBy(asc(departments.name)),
    ]);

    const currentYear = new Date().getUTCFullYear();
    const uniqueYears = new Set([
      currentYear,
      ...yearRows.map((row) => row.year),
    ]);

    return {
      years: [...uniqueYears]
        .toSorted((a, b) => b - a)
        .map((year) => ({ value: String(year), label: String(year) })),
      companies: companyRows
        .filter((row): row is { company: string } => Boolean(row.company))
        .map((row) => ({ value: row.company, label: row.company })),
      departments: departmentRows.map((row) => ({
        value: String(row.id),
        label: row.name,
      })),
    };
  },
);

function buildFilteredEmployeesQuery({
  organizationId,
  company,
  departmentId,
}: {
  organizationId: string;
  company: string | null;
  departmentId: number | null;
}) {
  return db
    .select({ id: employees.id })
    .from(employees)
    .where(
      and(
        eq(employees.organizationId, organizationId),
        eq(employees.isActive, true),
        ...(company ? [eq(employeeCompanyExpr, company)] : []),
        ...(departmentId !== null
          ? [eq(employees.departmentId, departmentId)]
          : []),
      ),
    );
}

function buildKsaProgress(
  target: { kHours: number; sHours: number; aHours: number },
  values: Partial<Record<"K" | "S" | "A", number>>,
) {
  return (
    [
      { key: "K" as const, targetHours: Number(target.kHours ?? 0) },
      { key: "S" as const, targetHours: Number(target.sHours ?? 0) },
      { key: "A" as const, targetHours: Number(target.aHours ?? 0) },
    ] satisfies Array<{ key: "K" | "S" | "A"; targetHours: number }>
  ).map((item) => {
    const approvedHours = Number(values[item.key] ?? 0);
    const percent =
      item.targetHours > 0
        ? Math.min((approvedHours / item.targetHours) * 100, 100)
        : 0;

    return {
      key: item.key,
      label: getTrainingCategoryLabel(item.key),
      approvedHours,
      targetHours: item.targetHours,
      percent,
      remainingHours: Math.max(item.targetHours - approvedHours, 0),
    };
  });
}

function buildEmployeeCards({
  approvedHours,
  pendingHours,
  rejectedHours,
  targetTotalHours,
  year,
}: {
  approvedHours: number;
  pendingHours: number;
  rejectedHours: number;
  targetTotalHours: number;
  year: number;
}) {
  const completionPercent =
    targetTotalHours > 0
      ? Math.min((approvedHours / targetTotalHours) * 100, 100)
      : 0;

  return [
    {
      title: "ชั่วโมงอนุมัติแล้ว",
      value: formatNumber(approvedHours),
      badge: ``,
      direction: approvedHours > 0 ? "up" : "neutral",
      description: "รวมชั่วโมงที่ผ่านการอนุมัติแล้วในปีที่เลือก",
      footer: `ปี ${year}`,
    },
    {
      title: "ชั่วโมงรอตรวจสอบ",
      value: formatNumber(pendingHours),
      badge: ``,
      direction: pendingHours > 0 ? "neutral" : "up",
      description: "รวมชั่วโมงจากรายการที่ยังรอผลหรือถูกขอแก้ไข",
      footer: `ปี ${year}`,
    },
    {
      title: "ชั่วโมงไม่อนุมัติ",
      value: formatNumber(rejectedHours),
      badge: ``,
      direction: rejectedHours > 0 ? "down" : "up",
      description: "รวมชั่วโมงจากรายการที่ถูกปฏิเสธ",
      footer: `ปี ${year}`,
    },
    {
      title: "ความคืบหน้า",
      value: formatPercent(completionPercent),
      badge: ``,
      direction: completionPercent >= 100 ? "up" : "neutral",
      description: "คิดจากชั่วโมงที่อนุมัติแล้วเทียบกับเป้าหมายประจำปี",
      footer: `อนุมัติแล้ว ${formatNumber(approvedHours)} / ${formatNumber(targetTotalHours)} ชั่วโมง`,
    },
  ] satisfies SummaryCard[];
}

async function buildAdminCards({
  organizationId,
  company,
  departmentId,
  year,
  pendingReviewCount,
}: {
  organizationId: string;
  company: string | null;
  departmentId: number | null;
  year: number;
  pendingReviewCount: number;
}) {
  const { start, end } = getYearRange(year);
  const filteredEmployees = buildFilteredEmployeesQuery({
    organizationId,
    company,
    departmentId,
  }).as("filtered_employees");
  const approvedHoursExpr = sql<number>`coalesce(${trainingRecords.approvedHours}, ${trainingRecords.hours})`;

  const employeeHours = await db
    .select({
      employeeId: filteredEmployees.id,
      approvedHours: sql<number>`coalesce(sum(${approvedHoursExpr}), 0)::float`,
    })
    .from(filteredEmployees)
    .leftJoin(
      trainingRecords,
      and(
        eq(trainingRecords.employeeId, filteredEmployees.id),
        eq(trainingRecords.organizationId, organizationId),
        eq(trainingRecords.approvalStatus, "approved"),
        gte(trainingRecords.trainingDate, start),
        lte(trainingRecords.trainingDate, end),
      ),
    )
    .groupBy(filteredEmployees.id);

  const targetMap = await getResolvedTrainingTargetsForEmployees({
    organizationId,
    employeeIds: employeeHours.map((row) => row.employeeId),
    year,
  });
  const totalEmployees = employeeHours.length;
  const passedTarget = employeeHours.filter((row) => {
    const targetTotalHours = Number(
      targetMap.get(row.employeeId)?.totalHours ?? 0,
    );
    return (
      targetTotalHours > 0 && Number(row.approvedHours ?? 0) >= targetTotalHours
    );
  }).length;
  const notPassedTarget = Math.max(totalEmployees - passedTarget, 0);

  return [
    {
      title: "พนักงานทั้งหมด",
      value: formatNumber(totalEmployees),
      badge: company || departmentId !== null ? "อัปเดตตามตัวกรองล่าสุด" : "",
      direction: totalEmployees > 0 ? "up" : "neutral",
      description: "จำนวนพนักงานในขอบเขตข้อมูลที่ HRD กำลังดูอยู่",
      footer: `ปี ${year}`,
    },
    {
      title: "ผ่านเป้าหมาย",
      value: formatNumber(passedTarget),
      badge: "",
      direction: passedTarget > 0 ? "up" : "neutral",
      description: "พนักงานที่มีชั่วโมงอนุมัติแล้วถึงหรือเกินเป้าหมาย",
      footer: "คำนวณจากชั่วโมงอนุมัติรายปี",
    },
    {
      title: "ยังไม่ผ่านเป้าหมาย",
      value: formatNumber(notPassedTarget),
      badge: "",
      direction: notPassedTarget > 0 ? "down" : "up",
      description: "พนักงานที่ยังต้องสะสมชั่วโมงเพิ่มให้ครบตามนโยบาย",
      footer: "ใช้เกณฑ์เดียวกับการวัดผ่านเป้าหมาย",
    },
    {
      title: "รอตรวจสอบ",
      value: formatNumber(pendingReviewCount),
      badge: "",
      direction: pendingReviewCount > 0 ? "neutral" : "up",
      description: "จำนวนรายการอบรมที่รอตรวจสอบหรือถูกขอแก้ไข",
      footer: `ปี ${year}`,
    },
  ] satisfies SummaryCard[];
}

const getOverviewDashboardData = cache(
  async (): Promise<OverviewDashboardData> => {
    const scope = await getOverviewScope();
    const filters = await getOverviewFilters();
    const options = await getOverviewFilterOptions();
    const policy = await getOverviewPolicy(scope.organizationId, filters.year);
    const { start, end } = getYearRange(filters.year);
    const isAdmin = isOrganizationAdminRole(scope.role);
    const selfEmployeeIds = isAdmin
      ? []
      : await getEmployeeIdsForUser({
          organizationId: scope.organizationId,
          userId: scope.userId,
        });
    const primaryEmployeeId = isAdmin
      ? null
      : await getPrimaryEmployeeIdForUser({
          organizationId: scope.organizationId,
          userId: scope.userId,
        });
    const employeeTarget =
      !isAdmin && primaryEmployeeId !== null
        ? await getResolvedTrainingTargetForEmployee({
            organizationId: scope.organizationId,
            employeeId: primaryEmployeeId,
            year: filters.year,
          })
        : null;

    const filteredEmployeeIds = isAdmin
      ? (
          await buildFilteredEmployeesQuery({
            organizationId: scope.organizationId,
            company: filters.company,
            departmentId: filters.departmentId,
          })
        ).map((row) => row.id)
      : selfEmployeeIds;

    if (isAdmin && filteredEmployeeIds.length === 0) {
      return {
        role: scope.role,
        businessRole: scope.businessRole,
        filters,
        options,
        cards: [
          {
            title: "พนักงานทั้งหมด",
            value: "0",
            badge: "ไม่พบข้อมูลตามตัวกรอง",
            direction: "neutral",
            description: "ไม่พบพนักงานที่ตรงกับบริษัทหรือแผนกที่เลือก",
            footer: `ปี ${filters.year}`,
          },
          {
            title: "ผ่านเป้าหมาย",
            value: "0",
            badge: `เป้าหมาย ${formatNumber(Number(policy.totalHours ?? 0))} ชั่วโมง`,
            direction: "neutral",
            description: "ยังไม่มีพนักงานที่ผ่านเป้าหมายในปีที่เลือก",
            footer: "คำนวณจากชั่วโมงอนุมัติรายปี",
          },
          {
            title: "ยังไม่ผ่านเป้าหมาย",
            value: "0",
            badge: "ไม่มีข้อมูลตามตัวกรอง",
            direction: "neutral",
            description: "ไม่มีพนักงานในขอบเขตที่ต้องติดตาม",
            footer: `ปี ${filters.year}`,
          },
          {
            title: "รอตรวจสอบ",
            value: "0",
            badge: "ไม่มีรายการค้างตรวจ",
            direction: "up",
            description: "ไม่มีรายการอบรมที่รอ HRD ตรวจสอบ",
            footer: `ปี ${filters.year}`,
          },
        ],
        employee: {
          ksaProgress: buildKsaProgress(policy, {}),
          recentActivity: [],
          announcements: [],
        },
        hrd: {
          monthlyTrend: getMonthLabels(filters.year).map((month) => ({
            month: month.label,
            approvedHours: 0,
            approvedRecords: 0,
          })),
          ksaDistribution: [],
          departmentRanking: [],
          topCourses: [],
        },
      };
    }

    const approvedHoursExpr = sql<number>`coalesce(${trainingRecords.approvedHours}, ${trainingRecords.hours})`;
    const scopedRecordsClause =
      filteredEmployeeIds.length > 0
        ? inArray(trainingRecords.employeeId, filteredEmployeeIds)
        : eq(trainingRecords.employeeId, -1);
    const where = and(
      eq(trainingRecords.organizationId, scope.organizationId),
      gte(trainingRecords.trainingDate, start),
      lte(trainingRecords.trainingDate, end),
      scopedRecordsClause,
    );

    const [
      statusRows,
      categoryRows,
      monthlyRows,
      recentRows,
      dashboardAnnouncementRows,
      departmentRows,
      topCourseRows,
      pendingCountResult,
    ] = await Promise.all([
      db
        .select({
          approvalStatus: trainingRecords.approvalStatus,
          totalHours: sql<number>`coalesce(sum(case
          when ${trainingRecords.approvalStatus} = 'approved' then ${approvedHoursExpr}
          else ${trainingRecords.hours}
        end), 0)::float`,
        })
        .from(trainingRecords)
        .where(where)
        .groupBy(trainingRecords.approvalStatus),
      db
        .select({
          category: trainingRecords.category,
          approvedHours: sql<number>`coalesce(sum(${approvedHoursExpr}), 0)::float`,
        })
        .from(trainingRecords)
        .where(and(where, eq(trainingRecords.approvalStatus, "approved")))
        .groupBy(trainingRecords.category),
      db
        .select({
          monthNumber: sql<number>`extract(month from ${trainingRecords.trainingDate})::int`,
          approvedHours: sql<number>`coalesce(sum(${approvedHoursExpr}), 0)::float`,
          approvedRecords: sql<number>`count(*)::int`,
        })
        .from(trainingRecords)
        .where(and(where, eq(trainingRecords.approvalStatus, "approved")))
        .groupBy(sql`extract(month from ${trainingRecords.trainingDate})`)
        .orderBy(asc(sql`extract(month from ${trainingRecords.trainingDate})`)),
      db
        .select({
          id: trainingRecords.id,
          employeeName: employees.fullName,
          employeeCode: employees.employeeCode,
          courseName: trainingRecords.courseName,
          status: trainingRecords.approvalStatus,
          trainingDate: trainingRecords.trainingDate,
        })
        .from(trainingRecords)
        .innerJoin(employees, eq(trainingRecords.employeeId, employees.id))
        .where(where)
        .orderBy(desc(trainingRecords.createdAt))
        .limit(5),
      getDashboardAnnouncementsForAccess({
        organizationId: scope.organizationId,
        permissions: scope.permissions,
        currentUserId: scope.userId,
        limit: 5,
      }),
      isAdmin
        ? db
            .select({
              label: sql<string>`coalesce(${departments.name}, 'ไม่ระบุแผนก')`,
              value: sql<number>`coalesce(sum(${approvedHoursExpr}), 0)::float`,
            })
            .from(trainingRecords)
            .innerJoin(employees, eq(trainingRecords.employeeId, employees.id))
            .leftJoin(departments, eq(employees.departmentId, departments.id))
            .where(and(where, eq(trainingRecords.approvalStatus, "approved")))
            .groupBy(sql`coalesce(${departments.name}, 'ไม่ระบุแผนก')`)
            .orderBy(desc(sql`coalesce(sum(${approvedHoursExpr}), 0)::float`))
            .limit(5)
        : Promise.resolve([]),
      isAdmin
        ? db
            .select({
              label: trainingRecords.courseName,
              value: sql<number>`coalesce(sum(${approvedHoursExpr}), 0)::float`,
            })
            .from(trainingRecords)
            .where(and(where, eq(trainingRecords.approvalStatus, "approved")))
            .groupBy(trainingRecords.courseName)
            .orderBy(
              desc(sql`coalesce(sum(${approvedHoursExpr}), 0)::float`),
              asc(trainingRecords.courseName),
            )
            .limit(5)
        : Promise.resolve([]),
      isAdmin
        ? db
            .select({
              value: sql<number>`count(*)::int`,
            })
            .from(trainingRecords)
            .where(and(where, eq(trainingRecords.approvalStatus, "pending")))
        : Promise.resolve([]),
    ]);

    const statusHours = {
      draft: 0,
      approved: 0,
      pending: 0,
      rejected: 0,
      needs_revision: 0,
    };

    for (const row of statusRows) {
      statusHours[row.approvalStatus] = Number(row.totalHours ?? 0);
    }

    const ksaValues = Object.fromEntries(
      categoryRows
        .filter(
          (row): row is { category: "K" | "S" | "A"; approvedHours: number } =>
            row.category === "K" ||
            row.category === "S" ||
            row.category === "A",
        )
        .map((row) => [row.category, Number(row.approvedHours ?? 0)]),
    ) as Partial<Record<"K" | "S" | "A", number>>;

    const ksaProgress = buildKsaProgress(employeeTarget ?? policy, ksaValues);

    const cards = isAdmin
      ? await buildAdminCards({
          organizationId: scope.organizationId,
          company: filters.company,
          departmentId: filters.departmentId,
          year: filters.year,
          pendingReviewCount: Number(pendingCountResult[0]?.value ?? 0),
        })
      : buildEmployeeCards({
          approvedHours: statusHours.approved,
          pendingHours: statusHours.pending + statusHours.needs_revision,
          rejectedHours: statusHours.rejected,
          targetTotalHours: Number(
            employeeTarget?.totalHours ?? policy.totalHours ?? 0,
          ),
          year: filters.year,
        });

    const monthlyMap = new Map(
      monthlyRows.map((row) => [row.monthNumber, row]),
    );

    return {
      role: scope.role,
      businessRole: scope.businessRole,
      filters,
      options,
      cards,
      employee: {
        ksaProgress,
        recentActivity: recentRows.map((row) => ({
          id: row.id,
          employeeName: row.employeeName,
          employeeCode: row.employeeCode,
          courseName: row.courseName,
          status: row.status,
          trainingDate: row.trainingDate.toISOString(),
          initials: getInitials(row.employeeName),
        })),
        announcements: dashboardAnnouncementRows.map((row) => ({
          id: row.id,
          title: row.title,
          content: row.content,
          isPin: row.is_pin,
          createdAt: row.created_at,
          href: `/dashboard/announcements/${row.id}`,
        })),
      },
      hrd: {
        monthlyTrend: getMonthLabels(filters.year).map((month) => {
          const row = monthlyMap.get(month.monthNumber);

          return {
            month: month.label,
            approvedHours: Number(row?.approvedHours ?? 0),
            approvedRecords: Number(row?.approvedRecords ?? 0),
          };
        }),
        ksaDistribution: ksaProgress.map((item, index) => ({
          label: item.key,
          value: item.approvedHours,
          fill: PIE_COLORS[index % PIE_COLORS.length],
        })),
        departmentRanking: departmentRows.map((row) => ({
          label: row.label,
          value: Number(row.value ?? 0),
        })),
        topCourses: topCourseRows.map((row) => ({
          label: row.label,
          value: Number(row.value ?? 0),
        })),
      },
    };
  },
);

export { getOverviewDashboardData, getOverviewFilterOptions };
