import { z } from "zod";
import { NextResponse } from "next/server";
import { requireAdminApiUser } from "@/lib/auth/admin";
import { callOpenAiJsonSchema } from "@/lib/ai/openai";
import { storeAiSuggestionFromEnvelope } from "@/lib/ai/suggestions";
import { getStrategicDiagnosticSnapshot } from "@/lib/strategic-diagnostic/server";
import { STRATEGIC_SECTION_KEYS, type StrategicSectionKey } from "@/lib/strategic-diagnostic/types";

const M2_PROMPT_VERSION = "m2_insights_v1";

const M2SectionKeySchema = z.enum(STRATEGIC_SECTION_KEYS);

const M2InsightResponseSchema = z.object({
  sectionGaps: z
    .array(
      z.object({
        sectionKey: M2SectionKeySchema,
        gap: z.string().min(8).max(240),
        impact: z.string().min(8).max(600),
        urgency: z.enum(["alta", "media", "baja"]),
      }),
    )
    .max(12),
  priorityActions: z
    .array(
      z.object({
        title: z.string().min(8).max(220),
        description: z.string().min(8).max(900),
        priority: z.enum(["alta", "media", "baja"]),
        ownerSuggestion: z.string().min(3).max(120),
        targetDateSuggestion: z.string().min(4).max(40),
      }),
    )
    .max(12),
  suggestedEvidence: z
    .array(
      z.object({
        sectionKey: M2SectionKeySchema,
        category: z.string().min(3).max(120),
        reason: z.string().min(8).max(600),
      }),
    )
    .max(20),
  suggestedFieldValues: z
    .array(
      z.object({
        sectionKey: M2SectionKeySchema,
        fieldPath: z.string().min(4).max(120),
        suggestedValue: z.string().min(1).max(500),
        rationale: z.string().min(8).max(700),
      }),
    )
    .max(20),
  confidence: z.enum(["low", "medium", "high"]),
});

const M2InsightJsonSchema = {
  type: "object",
  additionalProperties: false,
  required: ["sectionGaps", "priorityActions", "suggestedEvidence", "suggestedFieldValues", "confidence"],
  properties: {
    sectionGaps: {
      type: "array",
      items: {
        type: "object",
        additionalProperties: false,
        required: ["sectionKey", "gap", "impact", "urgency"],
        properties: {
          sectionKey: { type: "string", enum: STRATEGIC_SECTION_KEYS },
          gap: { type: "string" },
          impact: { type: "string" },
          urgency: { type: "string", enum: ["alta", "media", "baja"] },
        },
      },
    },
    priorityActions: {
      type: "array",
      items: {
        type: "object",
        additionalProperties: false,
        required: ["title", "description", "priority", "ownerSuggestion", "targetDateSuggestion"],
        properties: {
          title: { type: "string" },
          description: { type: "string" },
          priority: { type: "string", enum: ["alta", "media", "baja"] },
          ownerSuggestion: { type: "string" },
          targetDateSuggestion: { type: "string" },
        },
      },
    },
    suggestedEvidence: {
      type: "array",
      items: {
        type: "object",
        additionalProperties: false,
        required: ["sectionKey", "category", "reason"],
        properties: {
          sectionKey: { type: "string", enum: STRATEGIC_SECTION_KEYS },
          category: { type: "string" },
          reason: { type: "string" },
        },
      },
    },
    suggestedFieldValues: {
      type: "array",
      items: {
        type: "object",
        additionalProperties: false,
        required: ["sectionKey", "fieldPath", "suggestedValue", "rationale"],
        properties: {
          sectionKey: { type: "string", enum: STRATEGIC_SECTION_KEYS },
          fieldPath: { type: "string" },
          suggestedValue: { type: "string" },
          rationale: { type: "string" },
        },
      },
    },
    confidence: { type: "string", enum: ["low", "medium", "high"] },
  },
} as const;

function isSectionKey(value: string): value is StrategicSectionKey {
  return (STRATEGIC_SECTION_KEYS as readonly string[]).includes(value);
}

function normalizeEvidenceMetadata(value: unknown, fallback: Record<StrategicSectionKey, { count: number; categories: string[] }>) {
  if (!value || typeof value !== "object" || Array.isArray(value)) {
    return fallback;
  }

  const incoming = value as Record<string, unknown>;
  const normalized = { ...fallback };

  for (const key of STRATEGIC_SECTION_KEYS) {
    const sectionPayload = incoming[key];
    if (!sectionPayload || typeof sectionPayload !== "object" || Array.isArray(sectionPayload)) {
      continue;
    }

    const sectionRecord = sectionPayload as Record<string, unknown>;
    const countCandidate = Number(sectionRecord.count);
    const categories = Array.isArray(sectionRecord.categories)
      ? sectionRecord.categories
          .filter((item): item is string => typeof item === "string")
          .map((item) => item.trim())
          .filter(Boolean)
          .slice(0, 20)
      : [];

    normalized[key] = {
      count: Number.isFinite(countCandidate) && countCandidate >= 0 ? Math.floor(countCandidate) : normalized[key].count,
      categories: categories.length ? categories : normalized[key].categories,
    };
  }

  return normalized;
}

export async function POST(request: Request) {
  const user = await requireAdminApiUser();

  if (!user) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const snapshot = await getStrategicDiagnosticSnapshot(user.id);

  if (!snapshot) {
    return NextResponse.json({ error: "No existe un perfil organizacional para este usuario." }, { status: 400 });
  }

  const body = (await request.json().catch(() => ({}))) as Record<string, unknown>;
  const data = (body.data as unknown) ?? snapshot.data;

  const fallbackEvidenceMetadata = STRATEGIC_SECTION_KEYS.reduce(
    (accumulator, key) => {
      accumulator[key] = {
        count: snapshot.evidenceBySection[key].length,
        categories: Array.from(new Set(snapshot.evidenceBySection[key].map((item) => item.category))).slice(0, 20),
      };
      return accumulator;
    },
    {} as Record<StrategicSectionKey, { count: number; categories: string[] }>,
  );

  const evidenceMetadata = normalizeEvidenceMetadata(body.evidenceMetadata, fallbackEvidenceMetadata);

  const systemPrompt = [
    "Eres consultor senior de estrategia comercial para licitaciones publicas en Mexico.",
    "Analiza el diagnostico estrategico y prioriza acciones de alto impacto.",
    "No alteres puntajes deterministas: solo entrega recomendaciones asistidas.",
    "Responde exclusivamente JSON valido en espanol.",
  ].join(" ");

  const userPrompt = [
    "Diagnostico estrategico actual:",
    JSON.stringify({
      data,
      scores: snapshot.scores,
      evidenceMetadata,
    }),
    "",
    "Genera:",
    "- sectionGaps: brechas por seccion con impacto y urgencia.",
    "- priorityActions: acciones priorizadas con responsable sugerido y fecha objetivo.",
    "- suggestedEvidence: evidencia recomendada por seccion.",
    "- suggestedFieldValues: valores sugeridos para campos del formulario.",
    "",
    "Reglas para suggestedFieldValues:",
    "- sectionKey debe ser una seccion valida.",
    "- fieldPath debe usar notacion con punto (ej. technical.responseTimes).",
    "- suggestedValue debe ser texto aplicable directamente por el usuario.",
  ].join("\n");

  const envelope = await callOpenAiJsonSchema({
    promptVersion: M2_PROMPT_VERSION,
    systemPrompt,
    userPrompt,
    outputSchema: M2InsightResponseSchema,
    schemaName: "m2_strategic_insights",
    jsonSchema: M2InsightJsonSchema as unknown as Record<string, unknown>,
    model: process.env.OPENAI_M2_MODEL?.trim() || undefined,
  });

  const safeData =
    envelope.data ??
    ({
      sectionGaps: [],
      priorityActions: [],
      suggestedEvidence: [],
      suggestedFieldValues: [],
      confidence: envelope.confidence ?? "low",
    } satisfies z.infer<typeof M2InsightResponseSchema>);

  const filteredFieldValues = safeData.suggestedFieldValues.filter((item) => {
    if (!isSectionKey(item.sectionKey)) {
      return false;
    }

    return item.fieldPath.startsWith(`${item.sectionKey}.`);
  });

  const payload = {
    sectionGaps: safeData.sectionGaps,
    priorityActions: safeData.priorityActions,
    suggestedEvidence: safeData.suggestedEvidence,
    suggestedFieldValues: filteredFieldValues,
    confidence: safeData.confidence,
  };

  const persisted = await storeAiSuggestionFromEnvelope({
    userId: user.id,
    moduleKey: "M2",
    featureKey: "strategic_insights",
    subjectType: "organization",
    subjectId: snapshot.organizationId,
    inputForHash: {
      organizationId: snapshot.organizationId,
      data,
      evidenceMetadata,
      scores: snapshot.scores,
    },
    envelope,
    responsePayload: payload,
  });

  return NextResponse.json({
    ok: true,
    ...payload,
    suggestionId: persisted.suggestionId,
    meta: {
      engine: envelope.engine,
      model: envelope.model,
      usage: envelope.usage,
      warnings: envelope.warnings,
      confidence: envelope.confidence,
    },
  });
}
