import { NextResponse } from 'next/server';
import crypto from 'crypto';
import { db } from '@server/db/drizzle';
import { sql } from 'drizzle-orm';
import { initDatabase } from '@server/db/init';
import { v1ErrorBody } from '@server/middleware/v1Errors';
import { wrapRouteHandler } from '@server/logger/request';

/**
 * Dev-only smoke-test helper for the public v1 surface. It exercises the
 * pieces that don't show up in normal request traffic so misconfigurations
 * (missing api_keys table, withApiKey hashing drift, error envelope shape)
 * surface immediately during local development.
 *
 * Hard-disabled in production: returns 404 so the route doesn't even hint at
 * its existence on a deployed environment.
 *
 * Usage:
 *   curl http://localhost:5000/api/v1/_smoke
 */
async function handleGET() {
  if (process.env.NODE_ENV === 'production') {
    return NextResponse.json(v1ErrorBody('Not found', 'NOT_FOUND'), { status: 404 });
  }

  const checks: Array<{ name: string; ok: boolean; detail?: string }> = [];

  // 1. api_keys table exists and is queryable.
  try {
    await initDatabase();
    const { rows } = await db.execute(sql`
      SELECT COUNT(*)::int AS n FROM api_keys
    `);
    checks.push({ name: 'api_keys.table', ok: true, detail: `count=${(rows[0] as { n: number }).n}` });
  } catch (e) {
    checks.push({ name: 'api_keys.table', ok: false, detail: e instanceof Error ? e.message : String(e) });
  }

  // 2. SHA256 hashing matches what api-keys.service produces (cross-check).
  try {
    const sample = `rsk_${'a'.repeat(64)}`;
    const expected = crypto.createHash('sha256').update(sample).digest('hex');
    checks.push({ name: 'apiKey.hash', ok: expected.length === 64, detail: `len=${expected.length}` });
  } catch (e) {
    checks.push({ name: 'apiKey.hash', ok: false, detail: e instanceof Error ? e.message : String(e) });
  }

  // 3. Error envelope has the documented shape.
  try {
    const env = v1ErrorBody('hello', 'TEST_CODE', { extra: 1 });
    const ok =
      typeof env === 'object' &&
      env !== null &&
      'error' in env &&
      typeof env.error === 'object' &&
      env.error !== null &&
      env.error.code === 'TEST_CODE' &&
      env.error.message === 'hello' &&
      'details' in env.error;
    checks.push({ name: 'errorEnvelope.shape', ok });
  } catch (e) {
    checks.push({ name: 'errorEnvelope.shape', ok: false, detail: e instanceof Error ? e.message : String(e) });
  }

  // 4. openapi.json route resolves with the expected operation count.
  try {
    const url = new URL('/api/v1/openapi.json', `http://localhost:${process.env.PORT ?? 5000}`);
    const res = await fetch(url.toString(), { signal: AbortSignal.timeout(5000) });
    const body = (await res.json()) as { paths?: Record<string, Record<string, unknown>> };
    const opCount = Object.values(body.paths ?? {}).reduce(
      (sum, methods) => sum + Object.keys(methods ?? {}).length,
      0
    );
    checks.push({ name: 'openapi.operations', ok: opCount === 14, detail: `count=${opCount}` });
  } catch (e) {
    checks.push({ name: 'openapi.operations', ok: false, detail: e instanceof Error ? e.message : String(e) });
  }

  const allOk = checks.every((c) => c.ok);
  return NextResponse.json(
    {
      ok: allOk,
      env: process.env.NODE_ENV ?? 'development',
      checks,
    },
    { status: allOk ? 200 : 500 }
  );
}

export const GET = wrapRouteHandler(handleGET);
