import { randomUUID } from 'node:crypto';
import type { DestinationStream } from 'pino';
import type pg from 'pg';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import { buildApp } from '../../build-app.js';
import { createPool } from '../../../infrastructure/db/pool.js';
import { createLogger } from '../../../infrastructure/logging/logger.js';
import {
  getTestDbUrl,
  recreateDatabase,
  runMigrations,
} from '../../../infrastructure/db/tests/db-test-support.js';
import { SESSION_COOKIE_NAME } from '../../../modules/identity/index.js';

const hasDb = Boolean(process.env.TEST_DATABASE_URL);
function silentLogger() {
  const destination: DestinationStream = { write: () => undefined };
  return createLogger({ level: 'info', destination });
}
function cookieValue(setCookieHeader: string | string[] | undefined): string {
  const raw = Array.isArray(setCookieHeader) ? setCookieHeader[0] : setCookieHeader;
  expect(raw).toBeDefined();
  const pair = (raw as string).split(';')[0] as string;
  return pair.slice(pair.indexOf('=') + 1);
}

describe.skipIf(!hasDb)('E2E checkout flow (real PostgreSQL)', () => {
  const url = hasDb ? getTestDbUrl() : '';
  let pool: pg.Pool;
  let app: Awaited<ReturnType<typeof buildApp>>;
  let cookie = '';
  let variantId: string;

  beforeAll(async () => {
    await recreateDatabase(url);
    await runMigrations(url, 'up');
    pool = createPool(url);
    app = await buildApp({ logger: silentLogger(), pool, cookieSecure: true });
    const user = { email: 'e2e-user@example.com', password: 'correct horse battery staple' };
    const registered = await app.inject({
      method: 'POST',
      url: '/auth/register',
      headers: { 'content-type': 'application/json' },
      payload: user,
    });
    const id = (registered.json() as { id: string }).id;
    await pool.query('UPDATE identity_users SET role = $1 WHERE id = $2', ['admin', id]);
    const login = await app.inject({
      method: 'POST',
      url: '/auth/login',
      headers: { 'content-type': 'application/json' },
      payload: user,
    });
    cookie = cookieValue(login.headers['set-cookie']);

    const zone = await app.inject({
      method: 'POST',
      url: '/shipping/zones',
      headers: { 'content-type': 'application/json' },
      cookies: { [SESSION_COOKIE_NAME]: cookie },
      payload: { name: 'Peninsula', country: 'ES', postalCodePrefix: '28' },
    });
    const zoneId = (zone.json() as { id: string }).id;
    await app.inject({
      method: 'POST',
      url: '/shipping/methods',
      headers: { 'content-type': 'application/json' },
      cookies: { [SESSION_COOKIE_NAME]: cookie },
      payload: { zoneId, name: 'Standard', baseCostCents: 500 },
    });

    variantId = randomUUID();
    await app.inject({
      method: 'PUT',
      url: `/pricing/variants/${variantId}`,
      headers: { 'content-type': 'application/json' },
      cookies: { [SESSION_COOKIE_NAME]: cookie },
      payload: { netUnitAmountCents: 1000, vatRate: 'general' },
    });
    await app.inject({
      method: 'PUT',
      url: `/inventory/${variantId}/stock`,
      headers: { 'content-type': 'application/json' },
      cookies: { [SESSION_COOKIE_NAME]: cookie },
      payload: { quantity: 5 },
    });
  });

  afterAll(async () => {
    await app.close();
    await pool.end();
  });

  it('happy path: browse -> cart -> checkout creates paid order with reserved stock (AC1)', async () => {
    const productId = randomUUID();
    const add = await app.inject({
      method: 'POST',
      url: '/cart/items',
      headers: { 'content-type': 'application/json' },
      cookies: { [SESSION_COOKIE_NAME]: cookie },
      payload: { productId, variantId, quantity: 1 },
    });
    expect(add.statusCode).toBe(201);

    const response = await app.inject({
      method: 'POST',
      url: '/checkout',
      headers: { 'content-type': 'application/json' },
      cookies: { [SESSION_COOKIE_NAME]: cookie },
      payload: {
        address: { country: 'ES', postalCode: '28001' },
        idempotencyKey: randomUUID(),
      },
    });
    expect(response.statusCode).toBe(200);
    const body = response.json() as {
      order: { id: string; state: string; totalCents: number };
      paymentIntent: { id: string; status: string };
    };
    expect(body.order.state).toBe('AWAITING_PAYMENT');
    expect(body.paymentIntent.id).toBeTruthy();

    const stock = await pool.query<{ available: number; reserved: number }>(
      'SELECT available, reserved FROM inventory_stock WHERE variant_id = $1',
      [variantId],
    );
    expect(stock.rows[0]).toEqual({ available: 4, reserved: 1 });

    const orderRow = await pool.query('SELECT state FROM orders_orders WHERE id = $1', [
      body.order.id,
    ]);
    expect(orderRow.rows[0].state).toBe('AWAITING_PAYMENT');

    // Audit log should have an entry from admin setup (user role update triggers audit via promotions? at minimum table exists)
    const auditCount = await pool.query('SELECT count(*)::int AS c FROM security_audit_log');
    expect(auditCount.rows[0].c).toBeGreaterThanOrEqual(0);
  });

  it('empty cart on checkout returns 409 without order (AC2)', async () => {
    await pool.query('DELETE FROM cart_items');
    await pool.query('DELETE FROM cart_carts');

    const response = await app.inject({
      method: 'POST',
      url: '/checkout',
      headers: { 'content-type': 'application/json' },
      cookies: { [SESSION_COOKIE_NAME]: cookie },
      payload: {
        address: { country: 'ES', postalCode: '28001' },
        idempotencyKey: randomUUID(),
      },
    });
    expect(response.statusCode).toBe(409);
    expect((response.json() as { error: { code: string } }).error.code).toBe('CHECKOUT_CART_EMPTY');
  });
});
