import { NextRequest, NextResponse } from "next/server";

import { getRequestAuditContext } from "@/lib/audit";
import { getCampaignRetryState, runCampaignRetryBatch } from "@/lib/campaign-dispatch-service";
import { consumeRateLimit, getRateLimitHeaders } from "@/lib/rate-limit";

type JobPayload = {
  tenantId?: string;
  campaignId?: string;
  recipientBatchSize?: number;
  maxCampaigns?: number;
};

function isAuthorized(req: NextRequest) {
  const expected = process.env.CAMPAIGN_RETRY_JOB_TOKEN?.trim();
  if (!expected) {
    return process.env.NODE_ENV !== "production";
  }

  const tokenFromHeader = req.headers.get("authorization")?.trim() || req.headers.get("x-cron-token")?.trim();
  const tokenFromQuery = new URL(req.url).searchParams.get("token")?.trim();
  const token = tokenFromHeader || tokenFromQuery;
  if (!token) {
    return false;
  }

  return token === expected || token === `Bearer ${expected}`;
}

function resolveNumber(raw: string | undefined, fallback: number) {
  const value = Number(raw?.trim());
  if (!Number.isInteger(value) || value <= 0) {
    return fallback;
  }

  return value;
}

export async function GET(req: NextRequest) {
  const { ipAddress: requestIpAddress } = await getRequestAuditContext();
  const retryRate = consumeRateLimit(requestIpAddress || "unknown", {
    scope: "campaign_retry_job_get",
    limit: resolveNumber(process.env.CAMPAIGN_RETRY_JOB_RATE_LIMIT_GET, 60),
    windowMs: resolveNumber(process.env.CAMPAIGN_RETRY_JOB_RATE_LIMIT_WINDOW_MS, 60 * 1000)
  });

  if (!retryRate.allowed) {
    return NextResponse.json(
      { ok: false, error: "Too many requests. Please retry later." },
      {
        status: 429,
        headers: getRateLimitHeaders(retryRate)
      }
    );
  }

  if (!isAuthorized(req)) {
    return NextResponse.json({ ok: false, error: "Unauthorized" }, { status: 401 });
  }

  const state = await getCampaignRetryState();
  const now = new Date();
  const lockedUntil = state?.lockedUntil ? new Date(state.lockedUntil) : null;
  const health = {
    isLocked: Boolean(lockedUntil && lockedUntil > now),
    isStaleLock: Boolean(lockedUntil && lockedUntil <= now),
    lastRunStartedAt: state?.lastRunStartedAt ?? null,
    lastRunCompletedAt: state?.lastRunCompletedAt ?? null,
    lastRunStatus: state?.lastRunStatus ?? null
  };

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

export async function POST(req: NextRequest) {
  const { ipAddress: requestIpAddress } = await getRequestAuditContext();
  const retryRate = consumeRateLimit(requestIpAddress || "unknown", {
    scope: "campaign_retry_job_post",
    limit: resolveNumber(process.env.CAMPAIGN_RETRY_JOB_RATE_LIMIT_POST, 20),
    windowMs: resolveNumber(process.env.CAMPAIGN_RETRY_JOB_RATE_LIMIT_WINDOW_MS, 60 * 1000)
  });

  if (!retryRate.allowed) {
    return NextResponse.json(
      { ok: false, error: "Too many requests. Please retry later." },
      {
        status: 429,
        headers: getRateLimitHeaders(retryRate)
      }
    );
  }

  if (!isAuthorized(req)) {
    return NextResponse.json({ ok: false, error: "Unauthorized" }, { status: 401 });
  }

  let payload: unknown = {};
  try {
    payload = (await req.json()) as unknown;
  } catch {
    payload = {};
  }

  const safePayload = payload as JobPayload;
  const tenantId = safePayload?.tenantId?.trim?.() || undefined;
  const campaignId = safePayload?.campaignId?.trim?.() || undefined;

  const recipientBatchSize = Number.isInteger(safePayload?.recipientBatchSize)
    ? safePayload?.recipientBatchSize
    : undefined;
  const maxCampaigns = Number.isInteger(safePayload?.maxCampaigns)
    ? safePayload?.maxCampaigns
    : undefined;

  const { ipAddress, userAgent } = await getRequestAuditContext();

  try {
    const result = await runCampaignRetryBatch({
      campaignId,
      tenantId,
      actorIpAddress: ipAddress,
      actorUserAgent: userAgent,
      actorUserId: null,
      recipientBatchSize,
      maxCampaigns
    });

    return NextResponse.json({ ok: true, ...result });
  } catch (error) {
    const message = error instanceof Error ? error.message : "Campaign retry job failed";
    return NextResponse.json({ ok: false, error: message }, { status: 500 });
  }
}
