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

  beforeAll(async () => {
    await recreateDatabase(url);
    await runMigrations(url, 'up');
    pool = createPool(url);
    app = await buildApp({ logger: silentLogger(), pool, cookieSecure: true });

    const user = { email: 'inventory-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,
              email_confirmed = true,
              confirmed_at = now(),
              confirmation_token = null
        WHERE id = $2`,
      ['admin', id],
    );
    const login = await app.inject({
      method: 'POST',
      url: '/auth/login',
      headers: { 'content-type': 'application/json' },
      payload: user,
    });
    adminCookie = cookieValue(login.headers['set-cookie']);
  });

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

  it('returns paginated inventory rows with server-side search, filters and stats', async () => {
    const createProduct = async (name: string, slug: string, expirationDate?: string | null) => {
      const product = await app.inject({
        method: 'POST',
        url: '/products',
        headers: { 'content-type': 'application/json' },
        cookies: { [SESSION_COOKIE_NAME]: adminCookie },
        payload: { name, slug, state: 'active', expirationDate: expirationDate ?? null },
      });
      expect(product.statusCode).toBe(201);
      return product.json() as { id: string };
    };

    const productA = await createProduct('Avena bio', `avena-${randomUUID().slice(0, 8)}`);
    const productB = await createProduct(
      'Semillas lino',
      `lino-${randomUUID().slice(0, 8)}`,
      new Date(Date.now() + 10 * 86_400_000).toISOString().slice(0, 10),
    );

    const createVariant = async (productId: string, sku: string, ean: string) => {
      const response = await app.inject({
        method: 'POST',
        url: `/products/${productId}/variants`,
        headers: { 'content-type': 'application/json' },
        cookies: { [SESSION_COOKIE_NAME]: adminCookie },
        payload: { sku, ean },
      });
      expect(response.statusCode).toBe(201);
      return response.json() as { id: string };
    };

    const variantA = await createVariant(productA.id, `SKU-${randomUUID().slice(0, 8)}`, '111');
    const variantB = await createVariant(productB.id, `SKU-${randomUUID().slice(0, 8)}`, '222');

    const setPrice = async (
      variantId: string,
      netUnitAmountCents: number,
      costCents: number,
    ) => {
      const response = await app.inject({
        method: 'PUT',
        url: `/pricing/variants/${variantId}`,
        headers: { 'content-type': 'application/json' },
        cookies: { [SESSION_COOKIE_NAME]: adminCookie },
        payload: { netUnitAmountCents, costCents, vatRate: 'general' },
      });
      expect(response.statusCode).toBe(200);
    };

    const setStock = async (variantId: string, quantity: number) => {
      const response = await app.inject({
        method: 'PUT',
        url: `/inventory/${variantId}/stock`,
        headers: { 'content-type': 'application/json' },
        cookies: { [SESSION_COOKIE_NAME]: adminCookie },
        payload: { quantity },
      });
      expect(response.statusCode).toBe(200);
    };

    await setPrice(variantA.id, 1000, 600);
    await setPrice(variantB.id, 1000, 950);
    await setStock(variantA.id, 8);
    await setStock(variantB.id, 2);

    const search = await app.inject({
      method: 'GET',
      url: '/inventory/admin/overview?q=111&limit=10&offset=0',
      cookies: { [SESSION_COOKIE_NAME]: adminCookie },
    });
    expect(search.statusCode).toBe(200);
    expect(search.json()).toMatchObject({
      total: 1,
      stats: { inStock: 1, lowStock: 0, outOfStock: 0 },
      items: [
        {
          productName: 'Avena bio',
          variant: { ean: '111' },
          stock: { availableQuantity: 8 },
        },
      ],
    });

    const lowMargin = await app.inject({
      method: 'GET',
      url: '/inventory/admin/overview?filter=low_margin&limit=10&offset=0',
      cookies: { [SESSION_COOKIE_NAME]: adminCookie },
    });
    expect(lowMargin.statusCode).toBe(200);
    expect(lowMargin.json()).toMatchObject({
      total: 1,
      items: [
        {
          productName: 'Semillas lino',
          stock: { availableQuantity: 2 },
          marginPercent: 21,
        },
      ],
    });

    const expiring = await app.inject({
      method: 'GET',
      url: '/inventory/admin/overview?filter=expiring&limit=10&offset=0',
      cookies: { [SESSION_COOKIE_NAME]: adminCookie },
    });
    expect(expiring.statusCode).toBe(200);
    const expiringBody = expiring.json() as {
      total: number;
      items: Array<{ productName: string }>;
    };
    expect(expiringBody.total).toBe(2);
    expect(expiringBody.items.every((item) => item.productName === 'Semillas lino')).toBe(true);
  });
});
