/**
 * Auto-import public holidays for all active resources.
 *
 * For each resource, determines the applicable federal state from:
 *   1. resource.federalState (explicit, e.g. "BY")
 *   2. Falls back to federal-only holidays when no state is set
 *
 * Creates Vacation entries with type PUBLIC_HOLIDAY and status APPROVED.
 * Duplicate-safe: skips holidays that already exist (by date + type + resourceId).
 */

import { asHolidayResolverDb, getResolvedCalendarHolidays } from "./holiday-availability.js";

interface MinimalVacation {
  resourceId: string;
  startDate: Date;
  endDate: Date;
}

interface AutoImportDb {
  resource: {
    findMany: (args: any) => any;
  };
  country?: {
    findUnique: (args: any) => any;
  };
  metroCity?: {
    findUnique: (args: any) => any;
  };
  holidayCalendar?: {
    findMany: (args: any) => any;
  };
  vacation: {
    findMany: (args: any) => any;
    createMany: (args: any) => any;
  };
}

export interface AutoImportResult {
  year: number;
  holidaysCreated: number;
  resourcesProcessed: number;
  skippedExisting: number;
}

/**
 * Import public holidays for all active resources in a given year.
 * Returns the number of holiday vacation records created.
 */
export async function autoImportPublicHolidays(
  db: AutoImportDb,
  year: number,
): Promise<AutoImportResult> {
  const resources = await db.resource.findMany({
    where: { isActive: true },
    select: {
      id: true,
      federalState: true,
      countryId: true,
      metroCityId: true,
      country: { select: { code: true } },
      metroCity: { select: { name: true } },
    },
  });

  if (resources.length === 0) {
    return { year, holidaysCreated: 0, resourcesProcessed: 0, skippedExisting: 0 };
  }

  const nextYearStart = new Date(`${year}-01-01T00:00:00.000Z`);
  const nextYearEnd = new Date(`${year}-12-31T00:00:00.000Z`);
  const byHolidayProfile = new Map<string, typeof resources>();

  for (const resource of resources) {
    const profileKey = JSON.stringify({
      countryCode: resource.country?.code ?? null,
      federalState: resource.federalState ?? null,
      metroCityName: resource.metroCity?.name ?? null,
    });
    const group = byHolidayProfile.get(profileKey) ?? [];
    group.push(resource);
    byHolidayProfile.set(profileKey, group);
  }

  let totalCreated = 0;
  let totalSkipped = 0;

  for (const [, groupedResources] of byHolidayProfile) {
    const sample = groupedResources[0];
    if (!sample) {
      continue;
    }

    const holidays = await getResolvedCalendarHolidays(asHolidayResolverDb(db), {
      periodStart: nextYearStart,
      periodEnd: nextYearEnd,
      countryId: sample.countryId,
      countryCode: sample.country?.code ?? null,
      federalState: sample.federalState,
      metroCityId: sample.metroCityId,
      metroCityName: sample.metroCity?.name ?? null,
    });
    if (holidays.length === 0) continue;
    const resourceIds = groupedResources.map((resource: { id: string }) => resource.id);

    for (const holiday of holidays) {
      const holidayDate = new Date(holiday.date);

      // Find existing records for this date + type to skip duplicates
      const existing: MinimalVacation[] = await db.vacation.findMany({
        where: {
          resourceId: { in: resourceIds },
          type: "PUBLIC_HOLIDAY",
          startDate: holidayDate,
          endDate: holidayDate,
        },
        select: { resourceId: true, startDate: true, endDate: true },
      });

      const existingResourceIds = new Set(existing.map((v: MinimalVacation) => v.resourceId));
      const newResourceIds = resourceIds.filter((id: string) => !existingResourceIds.has(id));

      totalSkipped += existingResourceIds.size;

      if (newResourceIds.length === 0) continue;

      const records = newResourceIds.map((resourceId: string) => ({
        resourceId,
        type: "PUBLIC_HOLIDAY",
        status: "APPROVED",
        startDate: holidayDate,
        endDate: holidayDate,
        note: holiday.name,
        isHalfDay: false,
        approvedAt: new Date(),
      }));

      const result = await db.vacation.createMany({
        data: records,
        skipDuplicates: true,
      });

      totalCreated += result.count;
    }
  }

  return {
    year,
    holidaysCreated: totalCreated,
    resourcesProcessed: resources.length,
    skippedExisting: totalSkipped,
  };
}
