import { NextRequest, NextResponse } from "next/server";
import { getServerSession } from "next-auth";
import { AuthOptions } from "@/app/api/auth/[...nextauth]/authOptions";
import { z } from "zod";
import { normaliseRunFilters } from "@/lib/modellingRuns/model";
import {
  listModellingRuns,
  triggerModellingRun,
} from "@/lib/modellingRuns/server";

const filtersSchema = z.object({
  postcodes: z.array(z.string()).optional(),
  propertyTypes: z.array(z.string()).optional(),
  builtForms: z.array(z.string()).optional(),
  tagIds: z.array(z.union([z.string(), z.number()])).optional(),
});

const bodySchema = z.object({
  scenarioIds: z.array(z.string().regex(/^\d+$/)).min(1).max(50),
  filters: filtersSchema.default({}),
  previewedPropertyCount: z.number().int().nonnegative(),
});

function sessionToken(request: NextRequest): string | undefined {
  return (
    request.cookies.get("__Secure-next-auth.session-token")?.value ??
    request.cookies.get("next-auth.session-token")?.value
  );
}

// POST — record + dispatch a Modelling run (ADR-0008)
export async function POST(
  request: NextRequest,
  props: { params: Promise<{ portfolioId: string }> },
) {
  const session = await getServerSession(AuthOptions);
  if (!session?.user?.email) {
    return NextResponse.json({ error: "Unauthorised" }, { status: 401 });
  }
  const { portfolioId } = await props.params;
  if (!/^\d+$/.test(portfolioId)) {
    return NextResponse.json({ error: "Invalid portfolio id" }, { status: 400 });
  }

  let body: z.infer<typeof bodySchema>;
  try {
    body = bodySchema.parse(await request.json());
  } catch {
    return NextResponse.json({ error: "Invalid body" }, { status: 400 });
  }
  const normalised = normaliseRunFilters(body.filters);
  if (!normalised.ok) {
    return NextResponse.json({ error: normalised.error }, { status: 400 });
  }
  // Defence-in-depth: the distributor can't resolve `tag_ids` yet (backend ask
  // in docs/backend-asks/tag-ids-run-filter.md), so a tagged run would model the
  // unscoped superset while preview counted the tag subset — the exact
  // preview≠run divergence ADR-0008 forbids. Reject here so the block isn't
  // UI-only (the RunModellingClient guard is just the friendly first line).
  // Remove once the distributor lands `tag_ids`.
  if (normalised.filters.tagIds?.length) {
    return NextResponse.json(
      {
        error:
          "Running scenarios over tags isn't available yet — the modelling engine can't scope by tag. Remove the tag filter to run.",
      },
      { status: 400 },
    );
  }

  try {
    const outcome = await triggerModellingRun({
      portfolioId,
      scenarioIds: [...new Set(body.scenarioIds)],
      filters: normalised.filters,
      previewedPropertyCount: body.previewedPropertyCount,
      triggeredBy: session.user.email,
      sessionToken: sessionToken(request),
    });
    switch (outcome.kind) {
      case "ok":
        return NextResponse.json({ taskId: outcome.taskId }, { status: 202 });
      case "unknown_scenarios":
        return NextResponse.json(
          { error: `Unknown scenarios for this portfolio: ${outcome.missing.join(", ")}` },
          { status: 400 },
        );
      case "dispatch_failed":
        return NextResponse.json(
          { error: "Couldn't start modelling — please try again" },
          { status: outcome.status },
        );
    }
  } catch (err) {
    console.error("POST /modelling-runs error:", err);
    return NextResponse.json({ error: "Internal server error" }, { status: 500 });
  }
}

// GET — run history for the portfolio
export async function GET(
  _request: NextRequest,
  props: { params: Promise<{ portfolioId: string }> },
) {
  const session = await getServerSession(AuthOptions);
  if (!session?.user?.email) {
    return NextResponse.json({ error: "Unauthorised" }, { status: 401 });
  }
  const { portfolioId } = await props.params;
  if (!/^\d+$/.test(portfolioId)) {
    return NextResponse.json({ error: "Invalid portfolio id" }, { status: 400 });
  }
  try {
    return NextResponse.json({ runs: await listModellingRuns(portfolioId) });
  } catch (err) {
    console.error("GET /modelling-runs error:", err);
    return NextResponse.json({ error: "Internal server error" }, { status: 500 });
  }
}
