import { PrismaClient, type Prisma } from "@prisma/client";
import { getHolidayDemoCityNamesByCountry, getHolidayDemoProfileForIndex } from "./holiday-demo-profiles.js";
import { loadWorkspaceEnv } from "./load-workspace-env.js";
import { assertCapaKrakenDbTarget } from "./safe-destructive-env.js";

loadWorkspaceEnv();

const prisma = new PrismaClient();

type CountryRecord = {
  id: string;
  code: string;
};

function asJsonObject(value: Prisma.JsonValue | null | undefined): Record<string, Prisma.JsonValue> {
  if (!value || typeof value !== "object" || Array.isArray(value)) {
    return {};
  }

  return value as Record<string, Prisma.JsonValue>;
}

async function ensureCities(countryByCode: Map<string, CountryRecord>) {
  const cityNamesByCountry = getHolidayDemoCityNamesByCountry();
  const cityMap = new Map<string, { id: string }>();

  for (const [countryCode, cityNames] of Object.entries(cityNamesByCountry)) {
    const country = countryByCode.get(countryCode);
    if (!country) {
      continue;
    }

    for (const cityName of cityNames) {
      const city = await prisma.metroCity.upsert({
        where: {
          countryId_name: {
            countryId: country.id,
            name: cityName,
          },
        },
        update: {},
        create: {
          countryId: country.id,
          name: cityName,
        },
        select: { id: true },
      });
      cityMap.set(`${countryCode}:${cityName}`, city);
    }
  }

  return cityMap;
}

async function main() {
  assertCapaKrakenDbTarget("db:seed:holiday-demo-resources");
  console.log("Normalizing active resources for holiday demo profiles...");

  const countrySeeds = [
    { code: "DE", name: "Germany", dailyWorkingHours: 8 },
    { code: "ES", name: "Spain", dailyWorkingHours: 8 },
    { code: "IN", name: "India", dailyWorkingHours: 9 },
    { code: "US", name: "United States", dailyWorkingHours: 8 },
  ] as const;
  const countries = [];

  for (const countrySeed of countrySeeds) {
    countries.push(await prisma.country.upsert({
      where: { code: countrySeed.code },
      update: { name: countrySeed.name, dailyWorkingHours: countrySeed.dailyWorkingHours },
      create: countrySeed,
      select: { id: true, code: true },
    }));
  }

  const countryByCode = new Map(countries.map((country) => [country.code, country] as const));

  const cityByProfile = await ensureCities(countryByCode);
  const resources = await prisma.resource.findMany({
    where: { isActive: true },
    select: {
      id: true,
      eid: true,
      dynamicFields: true,
    },
    orderBy: { eid: "asc" },
  });

  let updated = 0;

  for (const [index, resource] of resources.entries()) {
    const profile = getHolidayDemoProfileForIndex(index);
    const country = countryByCode.get(profile.countryCode)!;
    const metroCity = cityByProfile.get(`${profile.countryCode}:${profile.cityName}`);

    if (!metroCity) {
      throw new Error(`Missing metro city for profile ${profile.countryCode}/${profile.cityName}`);
    }

    const dynamicFields = asJsonObject(resource.dynamicFields);

    await prisma.resource.update({
      where: { id: resource.id },
      data: {
        countryId: country.id,
        metroCityId: metroCity.id,
        federalState: profile.stateCode,
        dynamicFields: {
          ...dynamicFields,
          city: profile.cityName,
          holidayCountryCode: profile.countryCode,
          holidayStateCode: profile.stateCode,
        } as Prisma.InputJsonValue,
      },
    });
    updated += 1;
  }

  console.log(`Updated ${updated} active resources.`);
}

main()
  .catch((error) => {
    console.error(error);
    process.exit(1);
  })
  .finally(() => void prisma.$disconnect());
