/**
 * POST /api/analyzer/aggregate-reports
 * GET  /api/analyzer/aggregate-reports
 *
 * POST: queue a new aggregate report. Validates inputs, creates a 'pending'
 * row, fires runAggregateReport in the background, returns immediately with
 * the report id.
 *
 * GET: list reports (paginated, optionally filtered by user).
 */

import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
import { requireAuth } from '@/lib/auth-utils';
import postgresClient from '@/lib/services/postgres-client';
import {
  createAggregateReport,
  listAggregateReports,
  runAggregateReport,
} from '@/lib/services/analyzer/aggregate-persistence';
import {
  estimateAggregateReportCost,
  evaluateCost,
  recordCostAuditDecision,
} from '@/lib/services/analyzer/cost-guard';

const MAX_TICKETS_PER_REPORT = 100;

const PostBody = z.object({
  analysisIds: z.array(z.string().uuid()).max(MAX_TICKETS_PER_REPORT).optional(),
  ticketNumbers: z.array(z.string()).max(MAX_TICKETS_PER_REPORT).optional(),
  includeItglueContext: z.boolean().default(true),
  reportTitle: z.string().max(200).nullable().optional(),
  /** Acknowledges the per-request cost guard ($5 threshold). */
  confirmedCost: z.boolean().default(false),
});

interface FingerprintCheckRow {
  id: string;
  ticket_number: string;
  analysis_version: number;
  has_fingerprint: boolean;
  is_stale: boolean;
}

export async function POST(request: NextRequest) {
  const { session, error } = await requireAuth();
  if (error) return error;

  const body = await request.json().catch(() => ({}));
  const parsed = PostBody.safeParse(body);
  if (!parsed.success) {
    return NextResponse.json(
      { error: 'Invalid request body', details: parsed.error.issues },
      { status: 400 }
    );
  }
  const { analysisIds, ticketNumbers, includeItglueContext, reportTitle } = parsed.data;

  // Resolve analysisIds: explicit list > ticketNumbers (latest analysis per ticket).
  let resolvedIds: string[] = [];
  if (analysisIds && analysisIds.length > 0) {
    resolvedIds = analysisIds;
  } else if (ticketNumbers && ticketNumbers.length > 0) {
    const res = await postgresClient.query<{ id: string }>(
      `SELECT DISTINCT ON (ticket_number) id::text AS id
         FROM analyzer_analyses
        WHERE ticket_number = ANY($1::text[])
          AND status = 'complete'
        ORDER BY ticket_number, analysis_version DESC`,
      [ticketNumbers]
    );
    resolvedIds = res.rows.map((r) => r.id);
  } else {
    return NextResponse.json(
      { error: 'Provide analysisIds or ticketNumbers' },
      { status: 400 }
    );
  }

  if (resolvedIds.length === 0) {
    return NextResponse.json(
      { error: 'No matching complete analyses found for the given inputs' },
      { status: 400 }
    );
  }
  if (resolvedIds.length > MAX_TICKETS_PER_REPORT) {
    return NextResponse.json(
      {
        error: `Too many tickets (${resolvedIds.length}). Cap is ${MAX_TICKETS_PER_REPORT}.`,
      },
      { status: 400 }
    );
  }

  // Validate fingerprints + staleness.
  const validation = await postgresClient.query<FingerprintCheckRow>(
    `SELECT aa.id::text AS id,
            aa.ticket_number,
            aa.analysis_version,
            (aa.aggregate_fingerprint IS NOT NULL) AS has_fingerprint,
            (t.last_activity_date > aa.completed_at) AS is_stale
       FROM analyzer_analyses aa
       LEFT JOIN tickets t ON t.ticket_number = aa.ticket_number
                          AND t.is_deleted = false
      WHERE aa.id = ANY($1::uuid[])`,
    [resolvedIds]
  );
  const missingFingerprint = validation.rows
    .filter((r) => !r.has_fingerprint)
    .map((r) => `${r.ticket_number} v${r.analysis_version}`);
  const staleAnalyses = validation.rows
    .filter((r) => r.is_stale)
    .map((r) => `${r.ticket_number} v${r.analysis_version}`);

  if (missingFingerprint.length > 0) {
    return NextResponse.json(
      {
        error: 'Some analyses are missing aggregate_fingerprint',
        missingFingerprint,
        hint: 'Run scripts/backfill-fingerprints.ts to fill in legacy analyses, or re-analyze.',
      },
      { status: 400 }
    );
  }
  if (staleAnalyses.length > 0) {
    return NextResponse.json(
      {
        error:
          'Some selected tickets have new activity since their last analysis. Re-analyze first.',
        staleAnalyses,
      },
      { status: 400 }
    );
  }

  const userId = (session?.user as { id: string } | undefined)?.id ?? null;

  // Cost-guard evaluation. Hard-blocks at $50/day, asks for confirmation at >$5.
  const estimatedCost = estimateAggregateReportCost({
    ticketCount: resolvedIds.length,
    includeItglueContext: parsed.data.includeItglueContext,
  });
  const evaluation = await evaluateCost({
    userId,
    estimatedCost,
    confirmedCost: parsed.data.confirmedCost,
  });
  await recordCostAuditDecision({
    userId,
    action: 'aggregate_report',
    evaluation,
    context: { ticketCount: resolvedIds.length, includeItglueContext: parsed.data.includeItglueContext },
  });
  if (evaluation.decision === 'blocked') {
    return NextResponse.json(
      {
        error: 'Daily cost limit reached',
        message: evaluation.decisionReason,
        estimatedCost: evaluation.estimatedCost,
        dailySpendBefore: evaluation.dailySpendBefore,
      },
      { status: 403 }
    );
  }
  if (evaluation.decision === 'requires_confirmation') {
    return NextResponse.json(
      {
        error: 'Confirmation required',
        message: evaluation.decisionReason,
        estimatedCost: evaluation.estimatedCost,
        dailySpendBefore: evaluation.dailySpendBefore,
        requiresConfirmation: true,
        retryWith: { confirmedCost: true },
      },
      { status: 400 }
    );
  }

  const created = await createAggregateReport({
    generatedByUserId: userId,
    filterCriteria: { analysisIds: resolvedIds },
    analysisIds: resolvedIds,
    ticketCount: resolvedIds.length,
    includeItglueContext,
    reportTitle: reportTitle ?? null,
  });

  // Fire and forget — runner persists results when done.
  void runAggregateReport(created.id).catch((err) => {
    console.error('[ANALYZER-REPORT] background runner threw:', err);
  });

  return NextResponse.json({
    reportId: created.id,
    status: 'pending',
    ticketCount: resolvedIds.length,
  });
}

export async function GET(request: NextRequest) {
  const { error } = await requireAuth();
  if (error) return error;

  const url = new URL(request.url);
  const limit = Number(url.searchParams.get('limit') ?? 50);
  const offset = Number(url.searchParams.get('offset') ?? 0);
  const reports = await listAggregateReports({ limit, offset });
  return NextResponse.json({ reports });
}
