import type pg from 'pg';
import type { PricingRepository } from '../domain/ports.js';
import type { SetVariantPriceCommand, VariantPrice, VatRate } from '../domain/price.js';

interface PriceRow {
  variant_id: string;
  net_unit_amount_cents: number;
  offer_cents: number | null;
  cost_cents: number | null;
  vat_rate: VatRate;
  currency: 'EUR';
  created_at: Date;
  updated_at: Date;
}

export class PgPricingRepository implements PricingRepository {
  constructor(private readonly pool: pg.Pool) {}

  async findByVariantId(variantId: string): Promise<VariantPrice | undefined> {
    const result = await this.pool.query<PriceRow>(
      'SELECT * FROM pricing_variant_prices WHERE variant_id = $1',
      [variantId],
    );
    const row = result.rows[0];
    return row ? toVariantPrice(row) : undefined;
  }

  async seedVariantPrice(variantId: string): Promise<void> {
    await this.pool.query(
      `INSERT INTO pricing_variant_prices (variant_id, net_unit_amount_cents, offer_cents, cost_cents, vat_rate)
       VALUES ($1, 0, NULL, NULL, 'general')
       ON CONFLICT (variant_id) DO NOTHING`,
      [variantId],
    );
  }

  async setVariantPrice(input: SetVariantPriceCommand): Promise<VariantPrice> {
    const client = await this.pool.connect();
    try {
      await client.query('BEGIN');
      const previous = await client.query<PriceRow>(
        'SELECT * FROM pricing_variant_prices WHERE variant_id = $1 FOR UPDATE',
        [input.variantId],
      );
      const previousRow = previous.rows[0];
      const updated = await client.query<PriceRow>(
        `INSERT INTO pricing_variant_prices (variant_id, net_unit_amount_cents, offer_cents, cost_cents, vat_rate)
         VALUES ($1, $2, $3, $4, $5)
         ON CONFLICT (variant_id) DO UPDATE
           SET net_unit_amount_cents = EXCLUDED.net_unit_amount_cents,
               offer_cents = EXCLUDED.offer_cents,
               cost_cents = EXCLUDED.cost_cents,
               vat_rate = EXCLUDED.vat_rate,
               updated_at = now()
         RETURNING *`,
        [
          input.variantId,
          input.netUnitAmountCents,
          input.offerCents ?? null,
          input.costCents ?? null,
          input.vatRate,
        ],
      );
      const row = updated.rows[0];
      if (!row) {
        throw new Error('pricing_variant_prices upsert returned no row');
      }
      await client.query(
        `INSERT INTO pricing_price_history (
           variant_id,
           previous_net_unit_amount_cents,
           previous_vat_rate,
           previous_currency,
           new_net_unit_amount_cents,
           new_vat_rate,
           new_currency
         ) VALUES ($1, $2, $3, $4, $5, $6, $7)`,
        [
          input.variantId,
          previousRow?.net_unit_amount_cents ?? null,
          previousRow?.vat_rate ?? null,
          previousRow?.currency ?? null,
          row.net_unit_amount_cents,
          row.vat_rate,
          row.currency,
        ],
      );
      await client.query('COMMIT');
      return toVariantPrice(row);
    } catch (error) {
      await client.query('ROLLBACK');
      throw error;
    } finally {
      client.release();
    }
  }
}

function toVariantPrice(row: PriceRow): VariantPrice {
  return {
    variantId: row.variant_id,
    netUnitAmountCents: row.net_unit_amount_cents,
    offerCents: row.offer_cents,
    costCents: row.cost_cents,
    vatRate: row.vat_rate,
    currency: row.currency,
    createdAt: row.created_at,
    updatedAt: row.updated_at,
  };
}
