import { PrismaClient, ContentPageType, LegalJurisdictionLevel, OverallScoreMethod, PriorityLevel } from "@prisma/client";
import { readFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";

const prisma = new PrismaClient();
const __dirname = path.dirname(fileURLToPath(import.meta.url));

function yesNoOptions(questionKey) {
  return [
    { key: `${questionKey}-opt-yes`, label: "Si", weight: 5, sortOrder: 1 },
    { key: `${questionKey}-opt-no`, label: "No", weight: 0, sortOrder: 2 },
  ];
}

const moduleSeeds = [
  {
    key: "liderazgo-vision-estrategica",
    name: "Liderazgo y Vision Estrategica",
    description: "Capacidad de la direccion para definir y comunicar una vision clara orientada al valor publico.",
    sortOrder: 1,
    questions: [
      {
        key: "liderazgo-vision-estrategica-q1",
        prompt: "La direccion tiene una vision clara del proposito de la empresa mas alla de las ganancias?",
        helpText: null,
        sortOrder: 1,
        options: yesNoOptions("liderazgo-vision-estrategica-q1"),
      },
      {
        key: "liderazgo-vision-estrategica-q2",
        prompt: "Se comunica regularmente la estrategia empresarial a todo el equipo?",
        helpText: null,
        sortOrder: 2,
        options: yesNoOptions("liderazgo-vision-estrategica-q2"),
      },
      {
        key: "liderazgo-vision-estrategica-q3",
        prompt: "Existen objetivos medibles alineados con la generacion de valor publico?",
        helpText: null,
        sortOrder: 3,
        options: yesNoOptions("liderazgo-vision-estrategica-q3"),
      },
      {
        key: "liderazgo-vision-estrategica-q4",
        prompt: "La direccion participa activamente en la toma de decisiones estrategicas?",
        helpText: null,
        sortOrder: 4,
        options: yesNoOptions("liderazgo-vision-estrategica-q4"),
      },
      {
        key: "liderazgo-vision-estrategica-q5",
        prompt: "Se revisan y ajustan los planes estrategicos al menos anualmente?",
        helpText: null,
        sortOrder: 5,
        options: yesNoOptions("liderazgo-vision-estrategica-q5"),
      },
    ],
  },
  {
    key: "cultura-organizacional",
    name: "Cultura Organizacional",
    description: "Valores, comportamientos y mentalidad orientados a la excelencia y el impacto social.",
    sortOrder: 2,
    questions: [
      {
        key: "cultura-organizacional-q1",
        prompt: "La empresa promueve valores de integridad y etica en sus operaciones?",
        helpText: null,
        sortOrder: 1,
        options: yesNoOptions("cultura-organizacional-q1"),
      },
      {
        key: "cultura-organizacional-q2",
        prompt: "Existe un ambiente de trabajo colaborativo y respetuoso?",
        helpText: null,
        sortOrder: 2,
        options: yesNoOptions("cultura-organizacional-q2"),
      },
      {
        key: "cultura-organizacional-q3",
        prompt: "Se fomenta la mejora continua y el aprendizaje organizacional?",
        helpText: null,
        sortOrder: 3,
        options: yesNoOptions("cultura-organizacional-q3"),
      },
      {
        key: "cultura-organizacional-q4",
        prompt: "Los empleados conocen y practican los valores de la empresa?",
        helpText: null,
        sortOrder: 4,
        options: yesNoOptions("cultura-organizacional-q4"),
      },
      {
        key: "cultura-organizacional-q5",
        prompt: "Se reconoce y celebra el buen desempeno del equipo?",
        helpText: null,
        sortOrder: 5,
        options: yesNoOptions("cultura-organizacional-q5"),
      },
    ],
  },
  {
    key: "estructura-procesos",
    name: "Estructura y Procesos",
    description: "Organizacion interna, procedimientos y sistemas de gestion eficientes.",
    sortOrder: 3,
    questions: [
      {
        key: "estructura-procesos-q1",
        prompt: "Existen procesos documentados para las operaciones principales?",
        helpText: null,
        sortOrder: 1,
        options: yesNoOptions("estructura-procesos-q1"),
      },
      {
        key: "estructura-procesos-q2",
        prompt: "La empresa cuenta con un organigrama claro y funcional?",
        helpText: null,
        sortOrder: 2,
        options: yesNoOptions("estructura-procesos-q2"),
      },
      {
        key: "estructura-procesos-q3",
        prompt: "Se utilizan herramientas digitales para la gestion del negocio?",
        helpText: null,
        sortOrder: 3,
        options: yesNoOptions("estructura-procesos-q3"),
      },
      {
        key: "estructura-procesos-q4",
        prompt: "Existe un sistema de control de calidad en productos o servicios?",
        helpText: null,
        sortOrder: 4,
        options: yesNoOptions("estructura-procesos-q4"),
      },
      {
        key: "estructura-procesos-q5",
        prompt: "Se llevan registros financieros y contables actualizados?",
        helpText: null,
        sortOrder: 5,
        options: yesNoOptions("estructura-procesos-q5"),
      },
    ],
  },
  {
    key: "innovacion-sostenibilidad",
    name: "Innovacion y Sostenibilidad",
    description: "Capacidad de adaptacion, mejora continua y practicas sostenibles.",
    sortOrder: 4,
    questions: [
      {
        key: "innovacion-sostenibilidad-q1",
        prompt: "La empresa invierte en innovacion de productos, servicios o procesos?",
        helpText: null,
        sortOrder: 1,
        options: yesNoOptions("innovacion-sostenibilidad-q1"),
      },
      {
        key: "innovacion-sostenibilidad-q2",
        prompt: "Se implementan practicas de sostenibilidad ambiental?",
        helpText: null,
        sortOrder: 2,
        options: yesNoOptions("innovacion-sostenibilidad-q2"),
      },
      {
        key: "innovacion-sostenibilidad-q3",
        prompt: "Existe disposicion para adoptar nuevas tecnologias?",
        helpText: null,
        sortOrder: 3,
        options: yesNoOptions("innovacion-sostenibilidad-q3"),
      },
      {
        key: "innovacion-sostenibilidad-q4",
        prompt: "Se monitorean tendencias del mercado y competencia?",
        helpText: null,
        sortOrder: 4,
        options: yesNoOptions("innovacion-sostenibilidad-q4"),
      },
      {
        key: "innovacion-sostenibilidad-q5",
        prompt: "Se busca activamente la eficiencia en el uso de recursos?",
        helpText: null,
        sortOrder: 5,
        options: yesNoOptions("innovacion-sostenibilidad-q5"),
      },
    ],
  },
  {
    key: "impacto-social-equidad",
    name: "Impacto Social y Equidad",
    description: "Contribucion a la comunidad, inclusion y responsabilidad social.",
    sortOrder: 5,
    questions: [
      {
        key: "impacto-social-equidad-q1",
        prompt: "La empresa contribuye positivamente a la comunidad local?",
        helpText: null,
        sortOrder: 1,
        options: yesNoOptions("impacto-social-equidad-q1"),
      },
      {
        key: "impacto-social-equidad-q2",
        prompt: "Se promueve la equidad de genero en la organizacion?",
        helpText: null,
        sortOrder: 2,
        options: yesNoOptions("impacto-social-equidad-q2"),
      },
      {
        key: "impacto-social-equidad-q3",
        prompt: "Existen politicas de inclusion para grupos vulnerables?",
        helpText: null,
        sortOrder: 3,
        options: yesNoOptions("impacto-social-equidad-q3"),
      },
      {
        key: "impacto-social-equidad-q4",
        prompt: "Se considera el impacto social en las decisiones de negocio?",
        helpText: null,
        sortOrder: 4,
        options: yesNoOptions("impacto-social-equidad-q4"),
      },
      {
        key: "impacto-social-equidad-q5",
        prompt: "La empresa participa en iniciativas de responsabilidad social?",
        helpText: null,
        sortOrder: 5,
        options: yesNoOptions("impacto-social-equidad-q5"),
      },
    ],
  },
];

const recommendationSeeds = [
  {
    key: "rec-liderazgo-vision",
    moduleKey: "liderazgo-vision-estrategica",
    title: "Formalizar vision estrategica anual",
    description: "Define metas anuales medibles y comunica el avance con revisiones trimestrales para todo el equipo.",
    priority: PriorityLevel.HIGH,
  },
  {
    key: "rec-cultura-integridad",
    moduleKey: "cultura-organizacional",
    title: "Reforzar cultura de integridad y colaboracion",
    description: "Establece rutinas de reconocimiento y acciones concretas para fortalecer valores compartidos.",
    priority: PriorityLevel.MEDIUM,
  },
  {
    key: "rec-estructura-procesos",
    moduleKey: "estructura-procesos",
    title: "Estandarizar procesos y controles de calidad",
    description: "Documenta procesos clave y asigna responsables para mantener registros operativos y financieros al dia.",
    priority: PriorityLevel.HIGH,
  },
  {
    key: "rec-innovacion-sostenibilidad",
    moduleKey: "innovacion-sostenibilidad",
    title: "Activar plan de innovacion sostenible",
    description: "Prioriza proyectos de innovacion con impacto en eficiencia de recursos y seguimiento de tendencias del mercado.",
    priority: PriorityLevel.MEDIUM,
  },
  {
    key: "rec-impacto-social-equidad",
    moduleKey: "impacto-social-equidad",
    title: "Fortalecer estrategia de impacto social",
    description: "Define iniciativas de inclusion y equidad con indicadores concretos y resultados verificables.",
    priority: PriorityLevel.MEDIUM,
  },
  {
    key: "rec-gobernanza-global",
    moduleKey: null,
    title: "Instalar comite mensual de madurez empresarial",
    description: "Consolida resultados de los cinco modulos para priorizar inversiones y remover bloqueos.",
    priority: PriorityLevel.LOW,
  },
];

const workshopSeeds = [
  {
    key: "taller-liderazgo-hoja-ruta",
    moduleKey: "liderazgo-vision-estrategica",
    title: "Hoja de Ruta de Liderazgo Estrategico",
    summary: "Alinea vision, objetivos y ritmos de seguimiento para mejorar la direccion estrategica del equipo.",
    videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
    durationMinutes: 22,
    evidenceRequired: "Acta de sesion estrategica con objetivos trimestrales y responsables asignados.",
    learningObjectives: [
      "Definir prioridades estrategicas medibles",
      "Comunicar metas de forma transversal",
      "Establecer seguimiento mensual de resultados",
    ],
    sortOrder: 1,
  },
  {
    key: "taller-cultura-colaborativa",
    moduleKey: "cultura-organizacional",
    title: "Ambiente de Trabajo Colaborativo",
    summary: "Fortalece dinamicas de comunicacion y colaboracion para elevar desempeno y compromiso del equipo.",
    videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
    durationMinutes: 18,
    evidenceRequired: "Fotografia o acta de una dinamica de integracion aplicada con tu equipo.",
    learningObjectives: [
      "Implementar dinamicas de integracion",
      "Crear canales de comunicacion efectivos",
      "Manejar conflictos constructivamente",
    ],
    sortOrder: 1,
  },
  {
    key: "taller-procesos-auditables",
    moduleKey: "estructura-procesos",
    title: "Procesos Auditables y Control Operativo",
    summary: "Documenta procesos clave y define controles para mejorar trazabilidad y cumplimiento.",
    videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
    durationMinutes: 25,
    evidenceRequired: "Procedimiento documentado con roles, pasos, entradas y salidas del proceso.",
    learningObjectives: [
      "Mapear procesos criticos",
      "Definir controles de calidad",
      "Estandarizar evidencias operativas",
    ],
    sortOrder: 1,
  },
  {
    key: "taller-innovacion-sostenible",
    moduleKey: "innovacion-sostenibilidad",
    title: "Innovacion Aplicada con Enfoque Sostenible",
    summary: "Disena mejoras de alto impacto para reducir costos y aumentar diferenciacion competitiva.",
    videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
    durationMinutes: 20,
    evidenceRequired: "Ficha de iniciativa de innovacion con costo estimado, impacto y cronograma.",
    learningObjectives: [
      "Identificar oportunidades de mejora continua",
      "Evaluar impacto de iniciativas sostenibles",
      "Priorizar proyectos de innovacion factibles",
    ],
    sortOrder: 1,
  },
  {
    key: "taller-impacto-social-evidencia",
    moduleKey: "impacto-social-equidad",
    title: "Impacto Social y Equidad con Evidencia",
    summary: "Define acciones de impacto social medibles para fortalecer tu posicion en licitaciones.",
    videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
    durationMinutes: 24,
    evidenceRequired: "Plan de impacto social con objetivos, indicadores y responsables.",
    learningObjectives: [
      "Disenar iniciativas inclusivas",
      "Definir indicadores de impacto verificables",
      "Alinear acciones sociales con estrategia comercial",
    ],
    sortOrder: 1,
  },
];

const contentPageSeeds = [
  {
    slug: "faq-calculo-puntaje",
    type: ContentPageType.FAQ,
    title: "Como se calcula el puntaje global?",
    content:
      "El puntaje global se obtiene de la normalizacion de respuestas por modulo y un promedio ponderado entre modulos.",
    sortOrder: 1,
  },
  {
    slug: "faq-pausa-diagnostico",
    type: ContentPageType.FAQ,
    title: "Puedo pausar y continuar luego?",
    content:
      "Si. Las respuestas quedan guardadas por usuario para retomar en el ultimo punto completado del cuestionario.",
    sortOrder: 2,
  },
  {
    slug: "manual-ruta-completa",
    type: ContentPageType.MANUAL,
    title: "Ruta completa de uso de la plataforma",
    content:
      "Registro, verificacion de correo, onboarding, diagnostico por modulos, resultados y recomendaciones accionables.",
    sortOrder: 1,
  },
  {
    slug: "manual-interpretacion-dashboard",
    type: ContentPageType.MANUAL,
    title: "Interpretacion de dashboard",
    content:
      "Use barras para avance relativo por modulo y radar para comparacion de madurez entre capacidades clave.",
    sortOrder: 2,
  },
];

const legalDirectorySeeds = [
  {
    jurisdictionLevel: LegalJurisdictionLevel.FEDERAL,
    name: "Secretaria de la Funcion Publica (SFP)",
    scopeTagsJson: ["inconformidades", "sanciones", "organo-interno-control"],
    websiteUrl: "https://www.gob.mx/sfp",
    phone: null,
    email: null,
    stateCode: null,
    municipalityCode: null,
  },
  {
    jurisdictionLevel: LegalJurisdictionLevel.FEDERAL,
    name: "Tribunal Federal de Justicia Administrativa (TFJA)",
    scopeTagsJson: ["juicio-contencioso", "nulidad", "sanciones-administrativas"],
    websiteUrl: "https://www.tfja.gob.mx",
    phone: null,
    email: null,
    stateCode: null,
    municipalityCode: null,
  },
  {
    jurisdictionLevel: LegalJurisdictionLevel.FEDERAL,
    name: "Auditoria Superior de la Federacion (ASF)",
    scopeTagsJson: ["auditoria", "fiscalizacion", "cuenta-publica"],
    websiteUrl: "https://www.asf.gob.mx",
    phone: null,
    email: null,
    stateCode: null,
    municipalityCode: null,
  },
  {
    jurisdictionLevel: LegalJurisdictionLevel.FEDERAL,
    name: "CompraNet",
    scopeTagsJson: ["contrataciones", "licitaciones", "expedientes"],
    websiteUrl: "https://compranet.hacienda.gob.mx",
    phone: null,
    email: null,
    stateCode: null,
    municipalityCode: null,
  },
  {
    jurisdictionLevel: LegalJurisdictionLevel.FEDERAL,
    name: "Sistema Nacional Anticorrupcion",
    scopeTagsJson: ["anticorrupcion", "denuncias", "integridad"],
    websiteUrl: "https://www.sna.org.mx",
    phone: null,
    email: null,
    stateCode: null,
    municipalityCode: null,
  },
  {
    jurisdictionLevel: LegalJurisdictionLevel.STATE,
    name: "Secretaria de la Contraloria y Transparencia Gubernamental de Nuevo Leon",
    scopeTagsJson: ["inconformidades", "contraloria", "responsabilidades"],
    websiteUrl: "https://www.nl.gob.mx/dependencias/contraloria",
    phone: null,
    email: null,
    stateCode: "NL",
    municipalityCode: null,
  },
  {
    jurisdictionLevel: LegalJurisdictionLevel.STATE,
    name: "Tribunal de Justicia Administrativa de Nuevo Leon",
    scopeTagsJson: ["juicio-administrativo", "sanciones", "nulidad"],
    websiteUrl: "https://tjanl.gob.mx",
    phone: null,
    email: null,
    stateCode: "NL",
    municipalityCode: null,
  },
  {
    jurisdictionLevel: LegalJurisdictionLevel.STATE,
    name: "Auditoria Superior del Estado de Nuevo Leon",
    scopeTagsJson: ["auditoria", "fiscalizacion", "cuenta-publica-estatal"],
    websiteUrl: "https://www.asenl.gob.mx",
    phone: null,
    email: null,
    stateCode: "NL",
    municipalityCode: null,
  },
  {
    jurisdictionLevel: LegalJurisdictionLevel.STATE,
    name: "Sistema Estatal Anticorrupcion de Nuevo Leon",
    scopeTagsJson: ["anticorrupcion", "politica-estatal", "coordinacion"],
    websiteUrl: "https://www.seanl.mx",
    phone: null,
    email: null,
    stateCode: "NL",
    municipalityCode: null,
  },
];

async function upsertDiagnosticStructure() {
  const moduleKeys = moduleSeeds.map((moduleSeed) => moduleSeed.key);

  await prisma.diagnosticModule.deleteMany({
    where: {
      key: {
        notIn: moduleKeys,
      },
    },
  });

  for (const moduleSeed of moduleSeeds) {
    const moduleRecord = await prisma.diagnosticModule.upsert({
      where: { key: moduleSeed.key },
      update: {
        name: moduleSeed.name,
        description: moduleSeed.description,
        sortOrder: moduleSeed.sortOrder,
      },
      create: {
        key: moduleSeed.key,
        name: moduleSeed.name,
        description: moduleSeed.description,
        sortOrder: moduleSeed.sortOrder,
      },
    });

    const questionKeys = moduleSeed.questions.map((questionSeed) => questionSeed.key);
    await prisma.question.deleteMany({
      where: {
        moduleId: moduleRecord.id,
        key: {
          notIn: questionKeys,
        },
      },
    });

    for (const questionSeed of moduleSeed.questions) {
      const questionRecord = await prisma.question.upsert({
        where: { key: questionSeed.key },
        update: {
          moduleId: moduleRecord.id,
          prompt: questionSeed.prompt,
          helpText: questionSeed.helpText,
          sortOrder: questionSeed.sortOrder,
        },
        create: {
          key: questionSeed.key,
          moduleId: moduleRecord.id,
          prompt: questionSeed.prompt,
          helpText: questionSeed.helpText,
          sortOrder: questionSeed.sortOrder,
        },
      });

      const optionKeys = questionSeed.options.map((optionSeed) => optionSeed.key);
      await prisma.answerOption.deleteMany({
        where: {
          questionId: questionRecord.id,
          key: {
            notIn: optionKeys,
          },
        },
      });

      for (const optionSeed of questionSeed.options) {
        await prisma.answerOption.upsert({
          where: { key: optionSeed.key },
          update: {
            questionId: questionRecord.id,
            label: optionSeed.label,
            weight: optionSeed.weight,
            sortOrder: optionSeed.sortOrder,
          },
          create: {
            key: optionSeed.key,
            questionId: questionRecord.id,
            label: optionSeed.label,
            weight: optionSeed.weight,
            sortOrder: optionSeed.sortOrder,
          },
        });
      }
    }
  }
}

async function upsertRecommendations() {
  const recommendationKeys = recommendationSeeds.map((recommendationSeed) => recommendationSeed.key);
  const moduleLookup = new Map(
    (await prisma.diagnosticModule.findMany({ select: { id: true, key: true } })).map((moduleRecord) => [moduleRecord.key, moduleRecord.id]),
  );

  await prisma.recommendation.deleteMany({
    where: {
      key: {
        notIn: recommendationKeys,
      },
    },
  });

  for (const recommendationSeed of recommendationSeeds) {
    const moduleId = recommendationSeed.moduleKey ? moduleLookup.get(recommendationSeed.moduleKey) ?? null : null;

    await prisma.recommendation.upsert({
      where: { key: recommendationSeed.key },
      update: {
        moduleId,
        title: recommendationSeed.title,
        description: recommendationSeed.description,
        priority: recommendationSeed.priority,
        isTemplate: true,
      },
      create: {
        key: recommendationSeed.key,
        moduleId,
        title: recommendationSeed.title,
        description: recommendationSeed.description,
        priority: recommendationSeed.priority,
        isTemplate: true,
      },
    });
  }
}

async function upsertDevelopmentWorkshops() {
  const workshopKeys = workshopSeeds.map((workshopSeed) => workshopSeed.key);
  const moduleLookup = new Map(
    (await prisma.diagnosticModule.findMany({ select: { id: true, key: true } })).map((moduleRecord) => [moduleRecord.key, moduleRecord.id]),
  );

  await prisma.developmentWorkshop.deleteMany({
    where: {
      key: {
        notIn: workshopKeys,
      },
    },
  });

  for (const workshopSeed of workshopSeeds) {
    const moduleId = moduleLookup.get(workshopSeed.moduleKey);

    if (!moduleId) {
      // Skip orphan workshop seeds when module is unavailable.
      continue;
    }

    await prisma.developmentWorkshop.upsert({
      where: { key: workshopSeed.key },
      update: {
        moduleId,
        title: workshopSeed.title,
        summary: workshopSeed.summary,
        videoUrl: workshopSeed.videoUrl,
        durationMinutes: workshopSeed.durationMinutes,
        evidenceRequired: workshopSeed.evidenceRequired,
        learningObjectives: workshopSeed.learningObjectives,
        sortOrder: workshopSeed.sortOrder,
        isActive: true,
      },
      create: {
        key: workshopSeed.key,
        moduleId,
        title: workshopSeed.title,
        summary: workshopSeed.summary,
        videoUrl: workshopSeed.videoUrl,
        durationMinutes: workshopSeed.durationMinutes,
        evidenceRequired: workshopSeed.evidenceRequired,
        learningObjectives: workshopSeed.learningObjectives,
        sortOrder: workshopSeed.sortOrder,
        isActive: true,
      },
    });
  }
}

async function upsertContentPages() {
  for (const pageSeed of contentPageSeeds) {
    await prisma.contentPage.upsert({
      where: { slug: pageSeed.slug },
      update: {
        type: pageSeed.type,
        title: pageSeed.title,
        content: pageSeed.content,
        sortOrder: pageSeed.sortOrder,
        isPublished: true,
      },
      create: {
        slug: pageSeed.slug,
        type: pageSeed.type,
        title: pageSeed.title,
        content: pageSeed.content,
        sortOrder: pageSeed.sortOrder,
        isPublished: true,
      },
    });
  }
}

async function upsertDefaultScoringConfig() {
  await prisma.scoringConfig.upsert({
    where: { key: "default" },
    update: {
      lowScoreThreshold: 70,
      overallScoreMethod: OverallScoreMethod.EQUAL_ALL_MODULES,
      moduleWeights: {},
    },
    create: {
      key: "default",
      lowScoreThreshold: 70,
      overallScoreMethod: OverallScoreMethod.EQUAL_ALL_MODULES,
      moduleWeights: {},
    },
  });
}

async function upsertLegalDirectory() {
  for (const item of legalDirectorySeeds) {
    const existing = await prisma.legalDirectoryEntity.findFirst({
      where: {
        jurisdictionLevel: item.jurisdictionLevel,
        name: item.name,
        stateCode: item.stateCode,
        municipalityCode: item.municipalityCode,
      },
      select: { id: true },
    });

    if (existing) {
      await prisma.legalDirectoryEntity.update({
        where: { id: existing.id },
        data: {
          scopeTagsJson: item.scopeTagsJson,
          websiteUrl: item.websiteUrl,
          phone: item.phone,
          email: item.email,
          isActive: true,
        },
      });
      continue;
    }

    await prisma.legalDirectoryEntity.create({
      data: {
        jurisdictionLevel: item.jurisdictionLevel,
        name: item.name,
        scopeTagsJson: item.scopeTagsJson,
        websiteUrl: item.websiteUrl,
        phone: item.phone,
        email: item.email,
        stateCode: item.stateCode,
        municipalityCode: item.municipalityCode,
        isActive: true,
      },
    });
  }
}

async function loadMunicipalitySeeds() {
  const filePath = path.join(__dirname, "data", "municipalities.json");
  const content = await readFile(filePath, "utf-8");
  const parsed = JSON.parse(content);

  if (!Array.isArray(parsed)) {
    throw new Error("Invalid municipalities seed file format.");
  }

  return parsed.filter((item) => {
    return (
      item &&
      typeof item.stateCode === "string" &&
      typeof item.stateName === "string" &&
      typeof item.municipalityCode === "string" &&
      typeof item.municipalityName === "string"
    );
  });
}

async function upsertMunicipalities() {
  const municipalities = await loadMunicipalitySeeds();
  const activeKeys = municipalities.map((item) => `${item.stateCode}-${item.municipalityCode}`);

  await prisma.municipality.updateMany({
    where: {
      NOT: municipalities.map((item) => ({
        stateCode: item.stateCode,
        municipalityCode: item.municipalityCode,
      })),
    },
    data: {
      isActive: false,
    },
  });

  for (const municipality of municipalities) {
    await prisma.municipality.upsert({
      where: {
        stateCode_municipalityCode: {
          stateCode: municipality.stateCode,
          municipalityCode: municipality.municipalityCode,
        },
      },
      update: {
        stateName: municipality.stateName,
        municipalityName: municipality.municipalityName,
        openPortalUrl: municipality.openPortalUrl ?? null,
        openPortalType: municipality.openPortalType ?? "GENERIC",
        openSyncIntervalDays:
          typeof municipality.openSyncIntervalDays === "number" && municipality.openSyncIntervalDays > 0
            ? municipality.openSyncIntervalDays
            : 7,
        pntSubjectId: municipality.pntSubjectId ?? null,
        pntEntityId: municipality.pntEntityId ?? null,
        pntSectorId: municipality.pntSectorId ?? null,
        pntEntryUrl: municipality.pntEntryUrl ?? null,
        backupUrl: municipality.backupUrl ?? null,
        scrapingEnabled: municipality.scrapingEnabled !== false,
        isActive: municipality.isActive !== false,
      },
      create: {
        stateCode: municipality.stateCode,
        stateName: municipality.stateName,
        municipalityCode: municipality.municipalityCode,
        municipalityName: municipality.municipalityName,
        openPortalUrl: municipality.openPortalUrl ?? null,
        openPortalType: municipality.openPortalType ?? "GENERIC",
        openSyncIntervalDays:
          typeof municipality.openSyncIntervalDays === "number" && municipality.openSyncIntervalDays > 0
            ? municipality.openSyncIntervalDays
            : 7,
        pntSubjectId: municipality.pntSubjectId ?? null,
        pntEntityId: municipality.pntEntityId ?? null,
        pntSectorId: municipality.pntSectorId ?? null,
        pntEntryUrl: municipality.pntEntryUrl ?? null,
        backupUrl: municipality.backupUrl ?? null,
        scrapingEnabled: municipality.scrapingEnabled !== false,
        isActive: municipality.isActive !== false,
      },
    });
  }

  return activeKeys.length;
}

async function main() {
  await upsertDiagnosticStructure();
  await upsertDevelopmentWorkshops();
  await upsertRecommendations();
  await upsertContentPages();
  await upsertDefaultScoringConfig();
  await upsertLegalDirectory();
  const municipalitySeedCount = await upsertMunicipalities();

  const moduleCount = await prisma.diagnosticModule.count();
  const questionCount = await prisma.question.count();
  const optionCount = await prisma.answerOption.count();
  const workshopCount = await prisma.developmentWorkshop.count();
  const recommendationCount = await prisma.recommendation.count();
  const contentPageCount = await prisma.contentPage.count();
  const legalDirectoryCount = await prisma.legalDirectoryEntity.count({ where: { isActive: true } });
  const municipalityCount = await prisma.municipality.count({ where: { isActive: true } });

  console.log("Seed completed", {
    modules: moduleCount,
    questions: questionCount,
    answerOptions: optionCount,
    workshops: workshopCount,
    recommendations: recommendationCount,
    contentPages: contentPageCount,
    legalDirectory: legalDirectoryCount,
    municipalities: municipalityCount,
    municipalitySeedsProcessed: municipalitySeedCount,
  });
}

main()
  .catch((error) => {
    console.error("Seed failed", error);
    process.exitCode = 1;
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
