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/marketing";
import { canManageMarketing, mapMarketingInitiative } from "@/lib/marketing/persistence";
import { marketingLocations } from "@/lib/marketing/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 (!canManageMarketing(session.user.role, session.user.department)) {
    return NextResponse.json({ error: "Only owners or marketing leaders can edit initiatives." }, { status: 403 });
  }

  const initiativeId = context.params.id;
  const existing = await prisma.marketingInitiative.findFirst({
    where: {
      id: initiativeId,
      department: DepartmentKey.marketing,
    },
    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 attributionStart = input.attributionStart ? parseDueDate(input.attributionStart) : null;
  const attributionEnd = input.attributionEnd ? parseDueDate(input.attributionEnd) : null;
  const autoUpdatedAt = input.autoUpdatedAt ? parseDueDate(input.autoUpdatedAt) : 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 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: input.metrics.target,
        actual: input.metrics.actual,
        ticketsTarget: input.metrics.ticketsTarget,
        ticketsActual: input.metrics.ticketsActual,
        revenueTarget: input.metrics.revenueTarget,
        revenueActual: input.metrics.revenueActual,
        attributionChannel: input.attributionChannel ?? null,
        attributionPageId: input.attributionPageId ?? null,
        attributionCampaign: input.attributionCampaign ?? null,
        attributionStart,
        attributionEnd,
        autoActual: input.autoActual ?? null,
        autoTicketsActual: input.autoTicketsActual ?? null,
        autoRevenueActual: input.autoRevenueActual ?? null,
        autoUpdatedAt,
        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",
      },
    });

  });

  const initiative = await prisma.marketingInitiative.findUnique({
    where: { id: initiativeId },
    include: {
      contributors: true,
      locations: true,
      evidenceLinks: true,
      tasks: {
        include: {
          evidenceLinks: true,
        },
      },
      milestones: {
        include: {
          checkpoints: {
            orderBy: { createdAt: "asc" },
          },
        },
        orderBy: [{ sortOrder: "asc" }, { dueDate: "asc" }],
      },
    },
  });

  return NextResponse.json({
    ok: true,
    initiative: initiative ? mapMarketingInitiative(initiative) : null,
  });
}

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 (!canManageMarketing(session.user.role, session.user.department)) {
    return NextResponse.json({ error: "Only owners or marketing leaders can delete initiatives." }, { status: 403 });
  }

  const initiativeId = context.params.id;
  const existing = await prisma.marketingInitiative.findFirst({
    where: {
      id: initiativeId,
      department: DepartmentKey.marketing,
    },
    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 });
}
