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)('promotions flows (real PostgreSQL)', () => {
  const url = hasDb ? getTestDbUrl() : '';
  let pool: pg.Pool;
  let app: Awaited<ReturnType<typeof buildApp>>;
  let cookie = '';

  beforeAll(async () => {
    await recreateDatabase(url);
    await runMigrations(url, 'up');
    pool = createPool(url);
    app = await buildApp({ logger: silentLogger(), pool, cookieSecure: true });
    const user = {
      email: 'promotions-admin@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']);
  });

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

  async function seedCart(variantId: string, cents = 1000) {
    const productId = randomUUID();
    await app.inject({
      method: 'PUT',
      url: `/pricing/variants/${variantId}`,
      headers: { 'content-type': 'application/json' },
      cookies: { [SESSION_COOKIE_NAME]: cookie },
      payload: { netUnitAmountCents: cents, vatRate: 'general' },
    });
    await app.inject({
      method: 'PUT',
      url: `/inventory/${variantId}/stock`,
      headers: { 'content-type': 'application/json' },
      cookies: { [SESSION_COOKIE_NAME]: cookie },
      payload: { quantity: 10 },
    });
    await app.inject({
      method: 'POST',
      url: '/cart/items',
      headers: { 'content-type': 'application/json' },
      cookies: { [SESSION_COOKIE_NAME]: cookie },
      payload: { productId, variantId, quantity: 2, discountCents: 9999 },
    });
  }

  async function createPromo(code: string, overrides: Record<string, unknown> = {}) {
    return app.inject({
      method: 'POST',
      url: '/promotions',
      headers: { 'content-type': 'application/json' },
      cookies: { [SESSION_COOKIE_NAME]: cookie },
      payload: {
        code,
        type: 'percent',
        value: 1000,
        startsAt: '2026-01-01T00:00:00Z',
        endsAt: '2027-01-01T00:00:00Z',
        ...overrides,
      },
    });
  }

  it('applies valid promo code with server-side recalculated discount (AC1)', async () => {
    await seedCart(randomUUID(), 1000);
    await createPromo('SAVE10');

    const applied = await app.inject({
      method: 'POST',
      url: '/cart/promo-code',
      headers: { 'content-type': 'application/json' },
      cookies: { [SESSION_COOKIE_NAME]: cookie },
      payload: { code: 'save10', discountCents: 999999 },
    });

    expect(applied.statusCode).toBe(200);
    expect(applied.json()).toMatchObject({
      discount: { code: 'SAVE10', discountCents: 242 },
      totalBeforeDiscountCents: 2420,
      totalCents: 2178,
    });
  });

  it('rejects expired and exhausted promo codes with HTTP 422 (AC2)', async () => {
    await createPromo('OLD', { startsAt: '2020-01-01T00:00:00Z', endsAt: '2020-02-01T00:00:00Z' });
    await createPromo('USED', { usageLimit: 1 });
    await pool.query('UPDATE promotions_promotions SET usage_count = 1 WHERE code = $1', ['USED']);

    const expired = await app.inject({
      method: 'POST',
      url: '/cart/promo-code',
      headers: { 'content-type': 'application/json' },
      cookies: { [SESSION_COOKIE_NAME]: cookie },
      payload: { code: 'OLD' },
    });
    const exhausted = await app.inject({
      method: 'POST',
      url: '/cart/promo-code',
      headers: { 'content-type': 'application/json' },
      cookies: { [SESSION_COOKIE_NAME]: cookie },
      payload: { code: 'USED' },
    });

    expect(expired.statusCode).toBe(422);
    expect(exhausted.statusCode).toBe(422);
  });
});
