import { NextRequest, NextResponse } from 'next/server';
import { createHmac, timingSafeEqual } from 'node:crypto';
import { sql } from 'drizzle-orm';
import { db, schema, dbHelpers } from '@/lib/db';

function webhookSecret(): string | undefined {
  const raw =
    process.env['SCRIBA_WEBHOOK_SECRET_OUT']?.trim() ||
    process.env['SCRIBA_WEBHOOK_SECRET']?.trim();
  if (!raw) return undefined;
  const parts = raw.split(',').map((s) => s.trim()).filter(Boolean);
  return parts[parts.length - 1];
}

function verifySignature(body: string, header: string | null, secret: string): boolean {
  if (!header) return false;
  const match = header.match(/^(?:v1|sha256)=(.+)$/i);
  if (!match?.[1]) return false;
  const expected = createHmac('sha256', secret).update(body).digest('hex');
  try {
    return timingSafeEqual(Buffer.from(match[1], 'hex'), Buffer.from(expected, 'hex'));
  } catch {
    return false;
  }
}

type WebhookPayload = {
  event: string;
  runId: string;
  tenantId?: string;
  conversionId?: string | null;
  status: 'completed' | 'failed' | 'cancelled';
  timestamp?: string;
  accounting?: { totalTokens?: number; costUsd?: number };
  error?: string;
};

export async function POST(request: NextRequest) {
  const rawBody = await request.text();
  const secret = webhookSecret();

  if (secret) {
    const sig = request.headers.get('X-Scriba-Webhook-Signature');
    if (!verifySignature(rawBody, sig, secret)) {
      return NextResponse.json({ error: 'Invalid webhook signature' }, { status: 401 });
    }
  }

  let payload: WebhookPayload;
  try {
    payload = JSON.parse(rawBody) as WebhookPayload;
  } catch {
    return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 });
  }

  const { runId, conversionId, status, error } = payload;
  if (!runId || !status) {
    return NextResponse.json({ error: 'Missing runId or status' }, { status: 400 });
  }

  // Match an in-flight project by activeRunId or activeConversionId
  const rows = await db
    .select()
    .from(schema.projects)
    .where(
      sql`(${schema.projects.config}->>'activeRunId' = ${runId}) OR (${schema.projects.config}->>'activeConversionId' = ${conversionId ?? ''})`,
    )
    .limit(1);

  const project = rows[0];
  if (project) {
    const cfg = (project.config ?? {}) as Record<string, unknown>;
    const terminal = status === 'completed' || status === 'failed' || status === 'cancelled';

    if (terminal && project.status === 'converting') {
      await dbHelpers.updateProjectProgress(project.id, {
        status: status === 'completed' ? 'converting' : 'failed',
        config: {
          ...cfg,
          webhookLastEvent: {
            event: payload.event,
            runId,
            status,
            timestamp: payload.timestamp ?? new Date().toISOString(),
            accounting: payload.accounting ?? null,
            error: error ?? null,
          },
          ...(status !== 'completed' ? { activeRunId: null, activeConversionId: null } : {}),
        },
      });
    } else {
      await dbHelpers.updateProjectProgress(project.id, {
        config: {
          ...cfg,
          webhookLastEvent: {
            event: payload.event,
            runId,
            status,
            timestamp: payload.timestamp ?? new Date().toISOString(),
            accounting: payload.accounting ?? null,
            error: error ?? null,
          },
        },
      });
    }
  }

  return NextResponse.json({ received: true });
}
