import type { NormativeAnalysisResult } from "@/lib/normative-analysis/analyze";
import type { ProposalWorkflowState } from "@/lib/proposals/workflow-state";

export type WorkflowRequirementCategory = "administrativo" | "legal" | "tecnico" | "economico" | "general";
export type WorkflowRequirementSource = "official_format" | "required_checklist" | "critical_requirement" | "lock_in";

export type WorkflowRequirementSeed = {
  id: string;
  title: string;
  description: string;
  category: WorkflowRequirementCategory;
  mandatory: boolean;
  source: WorkflowRequirementSource;
};

export type WorkflowTechnicalSectionSeed = {
  id: string;
  title: string;
  description: string;
};

export type WorkflowMilestoneSeed = {
  id: string;
  title: string;
  dateIso: string | null;
  location: string;
  note: string;
  source: "ai" | "licitation" | "manual";
};

export function normalizeWorkflowKey(value: string) {
  return value
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "");
}

export function inferRequirementCategory(title: string): WorkflowRequirementCategory {
  const normalized = normalizeWorkflowKey(title);

  if (
    normalized.includes("anexo") ||
    normalized.includes("garantia") ||
    normalized.includes("fianza") ||
    normalized.includes("capacidad-financiera") ||
    normalized.includes("propuesta-economica")
  ) {
    return "economico";
  }

  if (
    normalized.includes("tecnica") ||
    normalized.includes("especificacion") ||
    normalized.includes("fabricante") ||
    normalized.includes("certificacion") ||
    normalized.includes("dmtf")
  ) {
    return "tecnico";
  }

  if (
    normalized.includes("integridad") ||
    normalized.includes("manifiesto") ||
    normalized.includes("impedimento") ||
    normalized.includes("acreditacion") ||
    normalized.includes("personalidad") ||
    normalized.includes("independiente") ||
    normalized.includes("legal")
  ) {
    return "legal";
  }

  if (normalized.includes("checklist") || normalized.includes("documentacion") || normalized.includes("administrativ")) {
    return "administrativo";
  }

  return "general";
}

function buildRequirementId(source: WorkflowRequirementSource, title: string, index: number) {
  const key = normalizeWorkflowKey(title) || `item-${index + 1}`;
  return `${source}-${key}`;
}

export function buildRequirementSeeds(result: NormativeAnalysisResult): WorkflowRequirementSeed[] {
  const buckets: WorkflowRequirementSeed[] = [];

  for (let index = 0; index < result.officialFormats.length; index += 1) {
    const item = result.officialFormats[index];
    const title = item.trim();
    if (!title) {
      continue;
    }

    buckets.push({
      id: buildRequirementId("official_format", title, index),
      title,
      description: "Formato oficial detectado en el analisis normativo.",
      category: inferRequirementCategory(title),
      mandatory: true,
      source: "official_format",
    });
  }

  for (let index = 0; index < result.requiredChecklist.length; index += 1) {
    const item = result.requiredChecklist[index];
    const title = item.title.trim();
    if (!title) {
      continue;
    }

    buckets.push({
      id: buildRequirementId("required_checklist", title, index),
      title,
      description: item.description,
      category: inferRequirementCategory(title),
      mandatory: true,
      source: "required_checklist",
    });
  }

  for (let index = 0; index < result.criticalRequirements.length; index += 1) {
    const item = result.criticalRequirements[index];
    const title = item.title.trim();
    if (!title) {
      continue;
    }

    buckets.push({
      id: buildRequirementId("critical_requirement", title, index),
      title,
      description: item.description,
      category: inferRequirementCategory(title),
      mandatory: true,
      source: "critical_requirement",
    });
  }

  for (let index = 0; index < result.lockIns.length; index += 1) {
    const item = result.lockIns[index];
    const title = item.title.trim();
    if (!title) {
      continue;
    }

    buckets.push({
      id: buildRequirementId("lock_in", title, index),
      title,
      description: item.impact,
      category: inferRequirementCategory(title),
      mandatory: true,
      source: "lock_in",
    });
  }

  return dedupeRequirementSeeds(buckets);
}

export function dedupeRequirementSeeds(requirements: WorkflowRequirementSeed[]) {
  const seen = new Set<string>();
  const deduped: WorkflowRequirementSeed[] = [];

  for (const item of requirements) {
    const signature = normalizeWorkflowKey(item.title);
    if (!signature || seen.has(signature)) {
      continue;
    }

    seen.add(signature);
    deduped.push(item);
  }

  return deduped;
}

export function mergeWorkflowRequirementsWithSeeds(
  existing: ProposalWorkflowState["requirements"],
  seeds: WorkflowRequirementSeed[],
): ProposalWorkflowState["requirements"] {
  const existingByTitle = new Map(existing.map((item) => [normalizeWorkflowKey(item.title), item]));

  return seeds.map((seed) => {
    const key = normalizeWorkflowKey(seed.title);
    const previous = existingByTitle.get(key);

    return {
      id: seed.id,
      title: seed.title,
      description: seed.description,
      category: seed.category,
      mandatory: seed.mandatory,
      source: seed.source,
      status: previous?.status ?? "pending",
      note: previous?.note ?? "",
      evidences: previous?.evidences ?? [],
    };
  });
}

function normalizeMilestoneTitle(title: string) {
  const normalized = normalizeWorkflowKey(title);
  return normalized || "evento";
}

function monthToNumber(monthRaw: string) {
  const month = monthRaw
    .toLowerCase()
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "");

  const mapping: Record<string, number> = {
    enero: 0,
    febrero: 1,
    marzo: 2,
    abril: 3,
    mayo: 4,
    junio: 5,
    julio: 6,
    agosto: 7,
    septiembre: 8,
    setiembre: 8,
    octubre: 9,
    noviembre: 10,
    diciembre: 11,
  };

  return mapping[month] ?? null;
}

function normalizeYear(value: number) {
  if (value < 100) {
    return value >= 70 ? 1900 + value : 2000 + value;
  }

  return value;
}

function buildIsoFromParts(year: number, month: number, day: number, hour = 0, minute = 0) {
  const date = new Date(Date.UTC(year, month, day, hour, minute, 0, 0));
  if (Number.isNaN(date.getTime())) {
    return null;
  }

  return date.toISOString();
}

function parseDateFromText(value: string) {
  const isoMatch = value.match(/\b(20\d{2}|19\d{2})[\/\-](\d{1,2})[\/\-](\d{1,2})(?:\s+a\s+las\s+(\d{1,2}):(\d{2})|\s+(\d{1,2}):(\d{2}))?/i);
  if (isoMatch) {
    const year = Number.parseInt(isoMatch[1] ?? "0", 10);
    const month = Number.parseInt(isoMatch[2] ?? "0", 10) - 1;
    const day = Number.parseInt(isoMatch[3] ?? "0", 10);
    const hour = Number.parseInt(isoMatch[4] ?? isoMatch[6] ?? "0", 10);
    const minute = Number.parseInt(isoMatch[5] ?? isoMatch[7] ?? "0", 10);
    if (month >= 0 && month <= 11 && day >= 1 && day <= 31) {
      return buildIsoFromParts(year, month, day, hour, minute);
    }
  }

  const slashMatch = value.match(/\b(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2,4})(?:\s+a\s+las\s+(\d{1,2}):(\d{2})|\s+(\d{1,2}):(\d{2}))?/i);
  if (slashMatch) {
    const day = Number.parseInt(slashMatch[1] ?? "0", 10);
    const month = Number.parseInt(slashMatch[2] ?? "0", 10) - 1;
    const year = normalizeYear(Number.parseInt(slashMatch[3] ?? "0", 10));
    const hour = Number.parseInt(slashMatch[4] ?? slashMatch[6] ?? "0", 10);
    const minute = Number.parseInt(slashMatch[5] ?? slashMatch[7] ?? "0", 10);
    if (month >= 0 && month <= 11 && day >= 1 && day <= 31) {
      return buildIsoFromParts(year, month, day, hour, minute);
    }
  }

  const namedMonthMatch = value.match(
    /\b(\d{1,2})\s+de\s+([a-zA-Z\u00C0-\u017F]+)\s+de\s+(\d{2,4})(?:\s+(?:a\s+las\s+)?(\d{1,2}):(\d{2}))?/i,
  );
  if (namedMonthMatch) {
    const day = Number.parseInt(namedMonthMatch[1] ?? "0", 10);
    const month = monthToNumber(namedMonthMatch[2] ?? "");
    const year = normalizeYear(Number.parseInt(namedMonthMatch[3] ?? "0", 10));
    const hour = Number.parseInt(namedMonthMatch[4] ?? "0", 10);
    const minute = Number.parseInt(namedMonthMatch[5] ?? "0", 10);
    if (month !== null && day >= 1 && day <= 31) {
      return buildIsoFromParts(year, month, day, hour, minute);
    }
  }

  return null;
}

function inferMilestoneTitle(fallbackTitle: string, text: string) {
  const lower = text.toLowerCase();
  if (lower.includes("junta") && lower.includes("aclar")) {
    return "Junta de aclaraciones";
  }
  if (lower.includes("venta de bases") || lower.includes("registro")) {
    return "Venta de bases y registro";
  }
  if (lower.includes("presentacion") && lower.includes("propuest")) {
    return "Presentacion de propuestas";
  }
  if (lower.includes("apertura") && lower.includes("economic")) {
    return "Apertura economica";
  }
  if (lower.includes("fallo") || lower.includes("adjudic")) {
    return "Fallo y adjudicacion";
  }
  if (lower.includes("visita") && lower.includes("sitio")) {
    return "Visita a sitio";
  }

  const compact = fallbackTitle.trim() || text.trim();
  if (compact.length <= 80) {
    return compact;
  }

  return `${compact.slice(0, 77).trimEnd()}...`;
}

function dedupeMilestones(seeds: WorkflowMilestoneSeed[]) {
  const seen = new Set<string>();
  const deduped: WorkflowMilestoneSeed[] = [];

  for (const seed of seeds) {
    const key = `${normalizeMilestoneTitle(seed.title)}|${seed.dateIso ?? ""}`;
    if (seen.has(key)) {
      continue;
    }
    seen.add(key);
    deduped.push(seed);
  }

  return deduped;
}

export function buildMilestoneSeedsFromAnalysis(result: NormativeAnalysisResult): WorkflowMilestoneSeed[] {
  const candidates = [
    ...result.requiredChecklist.map((item) => ({ title: item.title, description: item.description })),
    ...result.criticalRequirements.map((item) => ({ title: item.title, description: item.description })),
    { title: "Resumen ejecutivo", description: result.executiveSummary },
  ];

  const milestoneSeeds: WorkflowMilestoneSeed[] = [];

  for (const candidate of candidates) {
    const combined = `${candidate.title}. ${candidate.description}`.trim();
    const dateIso = parseDateFromText(combined);
    if (!dateIso) {
      continue;
    }

    const normalizedTitle = inferMilestoneTitle(candidate.title, combined);
    milestoneSeeds.push({
      id: `ai-milestone-${normalizeMilestoneTitle(normalizedTitle)}-${milestoneSeeds.length + 1}`,
      title: normalizedTitle,
      dateIso,
      location: "",
      note: candidate.description.length <= 240 ? candidate.description : `${candidate.description.slice(0, 237)}...`,
      source: "ai",
    });

    if (milestoneSeeds.length >= 10) {
      break;
    }
  }

  return dedupeMilestones(milestoneSeeds);
}

export function mergeWorkflowMilestonesWithSeeds(
  existing: ProposalWorkflowState["milestones"],
  seeds: WorkflowMilestoneSeed[],
): ProposalWorkflowState["milestones"] {
  const existingByTitle = new Map(existing.map((item) => [normalizeMilestoneTitle(item.title), item]));
  const usedExistingIds = new Set<string>();

  const merged = seeds.map((seed) => {
    const key = normalizeMilestoneTitle(seed.title);
    const previous = existingByTitle.get(key);
    if (previous) {
      usedExistingIds.add(previous.id);
    }

    return {
      id: previous?.id ?? seed.id,
      title: previous?.title ?? seed.title,
      dateIso: previous?.dateIso ?? seed.dateIso,
      location: previous?.location ?? seed.location,
      note: previous?.note ?? seed.note,
      source: previous?.source ?? seed.source,
    };
  });

  for (const item of existing) {
    if (usedExistingIds.has(item.id)) {
      continue;
    }
    merged.push(item);
  }

  return dedupeMilestones(merged).sort((a, b) => {
    if (!a.dateIso && !b.dateIso) {
      return a.title.localeCompare(b.title, "es-MX");
    }
    if (!a.dateIso) {
      return 1;
    }
    if (!b.dateIso) {
      return -1;
    }
    return new Date(a.dateIso).getTime() - new Date(b.dateIso).getTime();
  });
}

export function mergeWorkflowTechnicalSectionsWithSeeds(
  existing: ProposalWorkflowState["technicalSections"],
  seeds: WorkflowTechnicalSectionSeed[],
): ProposalWorkflowState["technicalSections"] {
  const existingByTitle = new Map(existing.map((item) => [normalizeWorkflowKey(item.title), item]));

  return seeds.map((seed) => {
    const key = normalizeWorkflowKey(seed.title);
    const previous = existingByTitle.get(key);

    return {
      id: seed.id,
      title: seed.title,
      description: seed.description,
      completed: previous?.completed ?? false,
    };
  });
}

export function applyAiSeedsToWorkflow(
  workflow: ProposalWorkflowState,
  args: {
    requirementSeeds: WorkflowRequirementSeed[];
    technicalSectionSeeds: WorkflowTechnicalSectionSeed[];
    milestoneSeeds?: WorkflowMilestoneSeed[];
  },
): ProposalWorkflowState {
  return {
    ...workflow,
    requirements: mergeWorkflowRequirementsWithSeeds(workflow.requirements, args.requirementSeeds),
    technicalSections: mergeWorkflowTechnicalSectionsWithSeeds(workflow.technicalSections, args.technicalSectionSeeds),
    milestones: args.milestoneSeeds ? mergeWorkflowMilestonesWithSeeds(workflow.milestones, args.milestoneSeeds) : workflow.milestones,
  };
}

export function buildTechnicalSectionSeeds(result: NormativeAnalysisResult): WorkflowTechnicalSectionSeed[] {
  const fromAi = result.preparationRecommendations.slice(0, 6).map((item, index) => ({
    id: `section-ai-${index + 1}`,
    title: item.title,
    description: item.description,
  }));

  const valueForMoneyActions = result.valueForMoney.actions.slice(0, 2).map((action, index) => ({
    id: `section-vfm-${index + 1}`,
    title: `Valor por dinero ${index + 1}`,
    description: action,
  }));

  const circularActions = result.circularEconomy.actions.slice(0, 2).map((action, index) => ({
    id: `section-circular-${index + 1}`,
    title: `Economia circular ${index + 1}`,
    description: action,
  }));

  const merged = [...fromAi, ...valueForMoneyActions, ...circularActions];
  const deduped = dedupeTechnicalSections(merged);

  if (deduped.length > 0) {
    return deduped.slice(0, 8);
  }

  return [
    {
      id: "section-default-1",
      title: "Documentacion Legal y Administrativa",
      description: "Integra los formatos y anexos legales solicitados en bases.",
    },
    {
      id: "section-default-2",
      title: "Propuesta Tecnica Detallada",
      description: "Describe alcance, metodologia, entregables y cumplimiento tecnico.",
    },
    {
      id: "section-default-3",
      title: "Acreditacion de Experiencia y Capacidad Tecnica",
      description: "Evidencia experiencia, cartas y certificaciones requeridas.",
    },
  ];
}

function dedupeTechnicalSections(sections: WorkflowTechnicalSectionSeed[]) {
  const seen = new Set<string>();
  const output: WorkflowTechnicalSectionSeed[] = [];

  for (const section of sections) {
    const key = normalizeWorkflowKey(section.title);
    if (!key || seen.has(key)) {
      continue;
    }

    seen.add(key);
    output.push(section);
  }

  return output;
}
