import { DepartmentKey } from "@prisma/client";
import { NextResponse } from "next/server";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import {
  completeCaptureAutomationRunFailure,
  completeCaptureAutomationRunSuccess,
  startCaptureAutomationRun,
} from "@/lib/capture";
import {
  publishHumanCapitalKpis,
  publishMarketingKpis,
  publishOperationsKpis,
  publishProjectsKpis,
} from "@/lib/kpis/publishers";
import { getWeekBounds } from "@/lib/kpis/date";
import { prisma } from "@/lib/prisma";
import { buildInsightsFromSnapshots } from "@/lib/marketing/meta";
import { mapSocialSnapshot } from "@/lib/marketing/persistence";
import { getHumanCapitalDashboardData } from "@/lib/human-capital";
import { getOperationsDashboardData } from "@/lib/operations";

type SyncResponse = {
  department: DepartmentKey;
  publishResult: {
    sectionKey: string;
    rowCount: number;
    weekStart: string;
  };
};

function normalizeDepartment(value: string | null | undefined): DepartmentKey | null {
  if (!value) {
    return null;
  }

  if (value === DepartmentKey.administracion) {
    return DepartmentKey.capital_humano;
  }

  if (
    value === DepartmentKey.marketing ||
    value === DepartmentKey.capital_humano ||
    value === DepartmentKey.operaciones ||
    value === DepartmentKey.proyectos
  ) {
    return value;
  }

  return null;
}

function resolveDepartmentForSync(input: {
  requestedDepartment: string | null;
  role: string | undefined;
  viewerDepartment: string | null | undefined;
}): DepartmentKey | null {
  const requested = normalizeDepartment(input.requestedDepartment);
  const viewerDepartment = normalizeDepartment(input.viewerDepartment);

  if (input.role === "owner") {
    return requested ?? DepartmentKey.marketing;
  }

  if (input.role !== "leader") {
    return null;
  }

  if (!viewerDepartment) {
    return null;
  }

  if (requested && requested !== viewerDepartment) {
    return null;
  }

  return viewerDepartment;
}

async function syncMarketing(weekStart?: string): Promise<SyncResponse> {
  const [snapshotsRaw, activeInitiatives] = await Promise.all([
    prisma.marketingSocialSnapshot.findMany({
      where: { department: DepartmentKey.marketing },
      orderBy: { capturedAt: "desc" },
      take: 20,
    }),
    prisma.marketingInitiative.count({
      where: {
        department: DepartmentKey.marketing,
        status: { in: ["planning", "in_progress", "completion"] },
      },
    }),
  ]);

  const insights = buildInsightsFromSnapshots(snapshotsRaw.map(mapSocialSnapshot));
  const sevenDay = insights.filter((item) => item.range === "7d");
  const growthPct7d =
    sevenDay.length > 0
      ? sevenDay.reduce((acc, item) => acc + item.followerGrowthPct, 0) / sevenDay.length
      : 0;
  const engagementPct7d =
    sevenDay.length > 0
      ? sevenDay.reduce((acc, item) => acc + item.engagementRatePct, 0) / sevenDay.length
      : 0;
  const instagram7d = sevenDay.find((item) => item.channel === "instagram");
  const instagramReach7d = instagram7d?.reach ?? 0;
  const instagramFollowers = instagram7d?.followersEnd ?? 0;

  const publishResult = await publishMarketingKpis({
    growthPct7d,
    engagementPct7d,
    activeInitiatives,
    syncStatus: "ready",
    instagramReach7d,
    instagramFollowers,
    weekStart,
  });

  return {
    department: DepartmentKey.marketing,
    publishResult,
  };
}

async function syncHumanCapital(weekStart?: string): Promise<SyncResponse> {
  const dashboard = await getHumanCapitalDashboardData();
  const publishResult = await publishHumanCapitalKpis({
    aggregateScore: dashboard.aggregateScore.totalScore,
    churnPct: dashboard.summary.monthlyChurnPct,
    medianTenureMonths: dashboard.summary.medianTenureMonths,
    headcount: dashboard.summary.activeHeadcount,
    weekStart,
  });

  return {
    department: DepartmentKey.capital_humano,
    publishResult,
  };
}

async function syncOperations(weekStart?: string): Promise<SyncResponse> {
  const dashboard = await getOperationsDashboardData();
  const publishResult = await publishOperationsKpis({
    overdueWorkOrders: dashboard.summary.overdueWorkOrders,
    pendingApprovals: dashboard.summary.pendingApprovals,
    plannedUnits: dashboard.summary.plannedUnits,
    forecastUnits: dashboard.summary.forecastUnits,
    weekStart,
  });

  return {
    department: DepartmentKey.operaciones,
    publishResult,
  };
}

async function syncProjects(weekStart?: string): Promise<SyncResponse> {
  const now = new Date();
  const initiatives = await prisma.marketingInitiative.findMany({
    where: {
      department: DepartmentKey.proyectos,
      projectsSchemaVersion: 2,
    },
    select: {
      status: true,
      dueDate: true,
      milestones: {
        select: {
          status: true,
          dueDate: true,
        },
      },
      tasks: {
        select: {
          status: true,
          dueDate: true,
        },
      },
    },
  });

  const activeProjects = initiatives.filter(
    (initiative) => initiative.status !== "results" && initiative.status !== "evaluation"
  ).length;
  const milestones = initiatives.flatMap((initiative) => initiative.milestones);
  const onTimeMilestonesPct =
    milestones.length > 0
      ? (milestones.filter((milestone) => {
          if (milestone.status === "completed") {
            return true;
          }

          return milestone.dueDate.getTime() >= now.getTime();
        }).length /
          milestones.length) *
        100
      : 0;
  const tasks = initiatives.flatMap((initiative) => initiative.tasks);
  const blockedTasks = tasks.filter((task) => task.status === "blocked").length;
  const overdueTasks = tasks.filter((task) => task.status !== "done" && task.dueDate.getTime() < now.getTime()).length;

  const publishResult = await publishProjectsKpis({
    activeProjects,
    onTimeMilestonesPct,
    blockedTasks,
    overdueTasks,
    weekStart,
  });

  return {
    department: DepartmentKey.proyectos,
    publishResult,
  };
}

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

  const { searchParams } = new URL(request.url);
  const requestedDepartment = searchParams.get("department");
  const weekStartInput = searchParams.get("weekStart") ?? undefined;
  const { weekStart } = getWeekBounds(weekStartInput);

  const department = resolveDepartmentForSync({
    requestedDepartment,
    role: session.user.role,
    viewerDepartment: session.user.department,
  });

  if (!department) {
    return NextResponse.json({ error: "Forbidden" }, { status: 403 });
  }

  const run = await startCaptureAutomationRun({
    department,
    weekStart,
    source: `${department}-manual-sync-v1`,
    triggeredById: session.user.id,
  });

  try {
    let response: SyncResponse;
    if (department === DepartmentKey.marketing) {
      response = await syncMarketing(weekStartInput);
    } else if (department === DepartmentKey.capital_humano) {
      response = await syncHumanCapital(weekStartInput);
    } else if (department === DepartmentKey.operaciones) {
      response = await syncOperations(weekStartInput);
    } else {
      response = await syncProjects(weekStartInput);
    }

    await completeCaptureAutomationRunSuccess({
      runId: run.id,
      department,
      weekStart: response.publishResult.weekStart,
      source: run.source,
      sectionKey: response.publishResult.sectionKey,
      rowsTouched: response.publishResult.rowCount,
    });

    return NextResponse.json({ ok: true, runId: run.id, ...response });
  } catch (error) {
    const message = error instanceof Error ? error.message : "Capture sync failed.";
    await completeCaptureAutomationRunFailure({
      runId: run.id,
      message,
    });

    return NextResponse.json({ error: message }, { status: 400 });
  }
}
