import { NextResponse } from "next/server";
import { DepartmentKey, MarketingInitiativeType, MarketingPublicOpinion } from "@prisma/client";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import type { Initiative, InitiativeStatus } from "@/lib/projects/types";
import { canManageProjects } from "@/lib/projects/persistence";
import { marketingLocations } from "@/lib/projects/mock";

type UpdateInitiativeBody = {
  initiative?: Initiative;
};

const ALLOWED_STATUS = new Set<InitiativeStatus>(["planning", "in_progress", "completion", "results", "evaluation"]);
const ALLOWED_TYPES = new Set<MarketingInitiativeType>([
  MarketingInitiativeType.evento,
  MarketingInitiativeType.campania,
  MarketingInitiativeType.cambio,
  MarketingInitiativeType.implementacion,
  MarketingInitiativeType.otro,
]);

const ALLOWED_OPINION = new Set<MarketingPublicOpinion>([
  MarketingPublicOpinion.positive,
  MarketingPublicOpinion.mixed,
  MarketingPublicOpinion.negative,
]);

function parseDueDate(value: string): Date | null {
  const parsed = new Date(value);
  if (Number.isNaN(parsed.getTime())) {
    return null;
  }

  return parsed;
}

export async function PATCH(request: Request, context: { params: { id: string } }) {
  const session = await getServerSession(authOptions);
  if (!session?.user) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  if (!canManageProjects(session.user.role, session.user.department)) {
    return NextResponse.json({ error: "Only owners or projects leaders can edit initiatives." }, { status: 403 });
  }

  const initiativeId = context.params.id;
  const existing = await prisma.marketingInitiative.findFirst({
    where: {
      id: initiativeId,
      department: DepartmentKey.proyectos,
    },
    select: { id: true },
  });

  if (!existing) {
    return NextResponse.json({ error: "Initiative not found." }, { status: 404 });
  }

  const body = (await request.json()) as UpdateInitiativeBody;
  const input = body.initiative;

  if (!input) {
    return NextResponse.json({ error: "Invalid payload." }, { status: 400 });
  }

  if (!ALLOWED_TYPES.has(input.type as MarketingInitiativeType)) {
    return NextResponse.json({ error: "Invalid initiative type." }, { status: 400 });
  }

  if (!ALLOWED_STATUS.has(input.status)) {
    return NextResponse.json({ error: "Invalid initiative status." }, { status: 400 });
  }

  if (!ALLOWED_OPINION.has(input.retro.opinionPublica as MarketingPublicOpinion)) {
    return NextResponse.json({ error: "Invalid public opinion value." }, { status: 400 });
  }

  const dueDate = parseDueDate(input.dueDate);
  if (!dueDate) {
    return NextResponse.json({ error: "Invalid due date." }, { status: 400 });
  }

  const completedAt = input.completedAt ? parseDueDate(input.completedAt) : null;

  const locationSet = new Set(marketingLocations.map((location) => location.id));
  const isGlobal = Boolean(input.isGlobal);
  const metricSelection = {
    score: input.metricSelection?.score ?? true,
    tickets: input.metricSelection?.tickets ?? true,
    revenue: input.metricSelection?.revenue ?? true,
  };
  const locationIds = input.locationIds.filter((locationId) => locationSet.has(locationId));
  if (!isGlobal && locationIds.length === 0) {
    return NextResponse.json({ error: "At least one valid location is required." }, { status: 400 });
  }
  if (!metricSelection.score && !metricSelection.tickets && !metricSelection.revenue) {
    return NextResponse.json({ error: "At least one KPI target must be enabled." }, { status: 400 });
  }

  const contributorIds = Array.from(new Set(input.contributorIds.filter((value) => value.trim().length > 0)));
  const evidenceLinks = Array.from(new Set(input.evidenceLinks.map((value) => value.trim()).filter((value) => value.length > 0)));
  const plannedCost = Number(input.plannedCost ?? 0) || 0;
  const actualCost = Number(input.actualCost ?? 0) || 0;
  const targetTicketPrice = Number(input.targetTicketPrice ?? 0) || 0;
  const actualTicketPrice = Number(input.actualTicketPrice ?? 0) || 0;
  const safeMetrics = {
    target: Number(input.metrics.target ?? 0) || 0,
    actual: Number(input.metrics.actual ?? 0) || 0,
    ticketsTarget: Math.round(Number(input.metrics.ticketsTarget ?? 0) || 0),
    ticketsActual: Math.round(Number(input.metrics.ticketsActual ?? 0) || 0),
    revenueTarget: Number(input.metrics.revenueTarget ?? 0) || 0,
    revenueActual: Number(input.metrics.revenueActual ?? 0) || 0,
  };
  if (
    safeMetrics.target < 0 ||
    safeMetrics.ticketsTarget < 0 ||
    safeMetrics.ticketsActual < 0 ||
    safeMetrics.revenueTarget < 0 ||
    plannedCost < 0 ||
    actualCost < 0 ||
    targetTicketPrice < 0 ||
    actualTicketPrice < 0
  ) {
    return NextResponse.json(
      { error: "Planned goals, counts, prices and costs must be non-negative. Actual outcomes can be negative." },
      { status: 400 }
    );
  }
  const isEvent = input.type === "evento";
  const isActualStage = input.status === "completion" || input.status === "results" || input.status === "evaluation";
  if (isEvent && isActualStage && metricSelection.tickets && safeMetrics.ticketsActual > 0 && actualTicketPrice <= 0) {
    return NextResponse.json({ error: "Actual ticket price is required when actual tickets are captured." }, { status: 400 });
  }
  const revenueTarget = isEvent ? safeMetrics.ticketsTarget * targetTicketPrice : safeMetrics.revenueTarget;
  const revenueActual = isEvent ? safeMetrics.ticketsActual * actualTicketPrice : safeMetrics.revenueActual;

  const updatedByName = session.user.name ?? session.user.email ?? "Usuario";

  await prisma.$transaction(async (tx) => {
    await tx.marketingInitiative.update({
      where: { id: initiativeId },
      data: {
        name: input.name.trim() || "Iniciativa",
        type: input.type,
        status: input.status,
        isGlobal,
        trackScore: metricSelection.score,
        trackTickets: metricSelection.tickets,
        trackRevenue: metricSelection.revenue,
        ownerId: input.ownerId || null,
        dueDate,
        completedAt,
        importanceWeight: input.importanceWeight,
        leadRating1to5: input.leadRating1to5,
        target: safeMetrics.target,
        actual: safeMetrics.actual,
        ticketsTarget: safeMetrics.ticketsTarget,
        ticketsActual: safeMetrics.ticketsActual,
        revenueTarget,
        revenueActual,
        plannedCost,
        actualCost,
        targetTicketPrice,
        actualTicketPrice,
        projectsSchemaVersion: 2,
        opinionPublica: input.retro.opinionPublica,
        queFunciono: input.retro.queFunciono,
        queNo: input.retro.queNo,
        proximoIntento: input.retro.proximoIntento,
        updatedById: session.user.id,
        updatedByName,
      },
    });

    await tx.marketingInitiativeContributor.deleteMany({
      where: { initiativeId },
    });

    if (contributorIds.length > 0) {
      await tx.marketingInitiativeContributor.createMany({
        data: contributorIds.map((userId) => ({ initiativeId, userId })),
        skipDuplicates: true,
      });
    }

    await tx.marketingInitiativeLocation.deleteMany({
      where: { initiativeId },
    });

    if (!isGlobal && locationIds.length > 0) {
      await tx.marketingInitiativeLocation.createMany({
        data: locationIds.map((locationId) => ({ initiativeId, locationId })),
        skipDuplicates: true,
      });
    }

    await tx.marketingInitiativeEvidence.deleteMany({
      where: { initiativeId },
    });

    if (evidenceLinks.length > 0) {
      await tx.marketingInitiativeEvidence.createMany({
        data: evidenceLinks.map((url) => ({
          initiativeId,
          url,
          createdById: session.user.id,
        })),
      });
    }

    await tx.marketingInitiativeEdit.create({
      data: {
        initiativeId,
        editedById: session.user.id,
        editedByName: updatedByName,
        summary: "Actualización de iniciativa",
      },
    });

  });

  return NextResponse.json({ ok: true });
}

export async function DELETE(_request: Request, context: { params: { id: string } }) {
  const session = await getServerSession(authOptions);
  if (!session?.user) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  if (!canManageProjects(session.user.role, session.user.department)) {
    return NextResponse.json({ error: "Only owners or projects leaders can delete initiatives." }, { status: 403 });
  }

  const initiativeId = context.params.id;
  const existing = await prisma.marketingInitiative.findFirst({
    where: {
      id: initiativeId,
      department: DepartmentKey.proyectos,
    },
    select: { id: true },
  });

  if (!existing) {
    return NextResponse.json({ error: "Initiative not found." }, { status: 404 });
  }

  await prisma.marketingInitiative.delete({
    where: { id: initiativeId },
  });

  return NextResponse.json({ ok: true });
}
