import type pg from 'pg';
import type { PaymentRepository } from '../domain/ports.js';
import type { PaymentEvent, PaymentStatus, PaymentTransaction } from '../domain/payment.js';

interface TransactionRow {
  id: string;
  provider: string;
  provider_event_id: string;
  provider_payment_id: string | null;
  order_id: string | null;
  amount_cents: number;
  currency: 'EUR';
  status: PaymentStatus;
  created_at: Date;
}

export class PgPaymentRepository implements PaymentRepository {
  constructor(private readonly pool: pg.Pool) {}

  async findByProviderEvent(
    provider: string,
    providerEventId: string,
  ): Promise<PaymentTransaction | undefined> {
    const result = await this.pool.query<TransactionRow>(
      'SELECT * FROM payments_transactions WHERE provider = $1 AND provider_event_id = $2',
      [provider, providerEventId],
    );
    const row = result.rows[0];
    return row ? toTransaction(row) : undefined;
  }

  async recordEvent(input: {
    provider: string;
    event: PaymentEvent;
  }): Promise<PaymentTransaction | undefined> {
    const result = await this.pool.query<TransactionRow>(
      `INSERT INTO payments_transactions (provider, provider_event_id, provider_payment_id, order_id, amount_cents, currency, status, raw)
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
       ON CONFLICT (provider, provider_event_id) DO NOTHING
       RETURNING *`,
      [
        input.provider,
        input.event.providerEventId,
        input.event.providerPaymentId,
        input.event.orderId,
        input.event.amountCents,
        input.event.currency,
        input.event.status,
        input.event.raw,
      ],
    );
    const row = result.rows[0];
    return row ? toTransaction(row) : undefined;
  }

  async listByOrderId(orderId: string): Promise<PaymentTransaction[]> {
    const result = await this.pool.query<TransactionRow>(
      'SELECT * FROM payments_transactions WHERE order_id = $1 ORDER BY created_at, id',
      [orderId],
    );
    return result.rows.map(toTransaction);
  }
}

function toTransaction(row: TransactionRow): PaymentTransaction {
  return {
    id: row.id,
    provider: row.provider,
    providerEventId: row.provider_event_id,
    providerPaymentId: row.provider_payment_id,
    orderId: row.order_id,
    amountCents: row.amount_cents,
    currency: row.currency,
    status: row.status,
    createdAt: row.created_at,
  };
}
