import { isDueSoonIso, isOverdueIso } from "@/lib/kpis/date";
import type { KpiRowStatus } from "@/lib/kpis/types";

const MONTH_INDEX: Record<string, number> = {
  ENERO: 1,
  FEBRERO: 2,
  MARZO: 3,
  ABRIL: 4,
  MAYO: 5,
  JUNIO: 6,
  JULIO: 7,
  AGOSTO: 8,
  SEPTIEMBRE: 9,
  SETIEMBRE: 9,
  OCTUBRE: 10,
  NOVIEMBRE: 11,
  DICIEMBRE: 12,
};

function normalizeText(value: string): string {
  return value
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .toUpperCase()
    .trim();
}

function parseNumeric(rawValue: string): number | null {
  const value = rawValue.replace(/\s+/g, "");

  if (/^-?\d{1,3}(,\d{3})+(\.\d+)?$/.test(value)) {
    return Number(value.replace(/,/g, ""));
  }

  if (/^-?\d+,\d+$/.test(value)) {
    return Number(value.replace(",", "."));
  }

  if (/^-?\d+(\.\d+)?$/.test(value)) {
    return Number(value);
  }

  return null;
}

export function parsePercent(value?: string | null): number | null {
  if (!value) {
    return null;
  }

  const match = value.match(/(-?\d+(?:[.,]\d+)?)\s*%/);
  if (!match) {
    return null;
  }

  return parseNumeric(match[1]) ?? null;
}

export function parseNumber(value?: string | null): number | null {
  if (!value) {
    return null;
  }

  const match = value.match(/-?\d{1,3}(?:,\d{3})*(?:\.\d+)?|-?\d+(?:[.,]\d+)?/);
  if (!match) {
    return null;
  }

  return parseNumeric(match[0]) ?? null;
}

export function parseDueDateIso(value: string | null | undefined, weekStartIso: string): string | null {
  if (!value) {
    return null;
  }

  const normalized = normalizeText(value);
  const weekYear = Number(weekStartIso.slice(0, 4));

  if (normalized.includes("EN UNA SEMANA")) {
    const start = new Date(`${weekStartIso}T00:00:00.000Z`);
    const next = new Date(start.getTime() + 7 * 24 * 60 * 60 * 1000);
    return next.toISOString().slice(0, 10);
  }

  const numericDate = normalized.match(/\b(\d{1,2})\/(\d{1,2})(?:\/(\d{2,4}))?\b/);
  if (numericDate) {
    const day = Number(numericDate[1]);
    const month = Number(numericDate[2]);
    const parsedYear = numericDate[3] ? Number(numericDate[3]) : weekYear;
    const year = parsedYear < 100 ? parsedYear + 2000 : parsedYear;

    if (month >= 1 && month <= 12 && day >= 1 && day <= 31) {
      return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
    }
  }

  const monthMatch = normalized.match(/\b(ENERO|FEBRERO|MARZO|ABRIL|MAYO|JUNIO|JULIO|AGOSTO|SEPTIEMBRE|SETIEMBRE|OCTUBRE|NOVIEMBRE|DICIEMBRE)\b/);
  if (!monthMatch) {
    return null;
  }

  const month = MONTH_INDEX[monthMatch[1]];
  if (!month) {
    return null;
  }

  const nearMonthNumber = normalized.match(
    new RegExp(`(?:^|\\s)(\\d{1,2})(?!\\d)\\s*${monthMatch[1]}|${monthMatch[1]}\\s*(\\d{1,2})(?!\\d)`)
  );
  const day = Number(nearMonthNumber?.[1] ?? nearMonthNumber?.[2] ?? 15);

  if (day < 1 || day > 31) {
    return null;
  }

  return `${weekYear}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
}

export function deriveKpiStatus(input: {
  compliancePct: number | null;
  quantityValue: number | null;
  objectiveIndicatorText?: string | null;
  dueDateIso?: string | null;
  todayIso: string;
}): KpiRowStatus {
  const { compliancePct, quantityValue, objectiveIndicatorText, dueDateIso, todayIso } = input;

  if (compliancePct !== null) {
    if (compliancePct >= 90) {
      return "on_track";
    }

    if (compliancePct >= 60) {
      return "watch";
    }

    return "risk";
  }

  if (dueDateIso && isOverdueIso(dueDateIso, todayIso)) {
    return "risk";
  }

  if (dueDateIso && isDueSoonIso(dueDateIso, todayIso, 7)) {
    return "watch";
  }

  if (quantityValue !== null && objectiveIndicatorText && normalizeText(objectiveIndicatorText).includes("PLAN")) {
    return "watch";
  }

  return "no_score";
}

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

export function buildRowKey(parts: Array<string | null | undefined>): string {
  const merged = parts.filter((value) => value && value.trim().length > 0).join("|").trim();
  return normalizeRowKey(merged || "row");
}
