import type pg from 'pg';
import type { ProductRichDataRepository } from '../domain/ports.js';
import type { NutritionSource, ProductRichData, RichDataPatch } from '../domain/variant.js';

interface RichDataRow {
  product_id: string;
  ingredients: string | null;
  allergens: string[];
  nutrition: Record<string, unknown> | null;
  nutrition_source: NutritionSource | null;
  is_organic: boolean;
  organic_certification: string | null;
  created_at: Date;
  updated_at: Date;
}

export class PgProductRichDataRepository implements ProductRichDataRepository {
  constructor(private readonly pool: pg.Pool) {}

  async findByProductId(productId: string): Promise<ProductRichData | undefined> {
    const result = await this.pool.query<RichDataRow>(
      'SELECT * FROM catalog_product_rich_data WHERE product_id = $1',
      [productId],
    );
    const row = result.rows[0];
    return row ? toRichData(row) : undefined;
  }

  async upsert(productId: string, patch: RichDataPatch): Promise<ProductRichData> {
    const current = await this.findByProductId(productId);
    const next = {
      ingredients:
        patch.ingredients !== undefined ? patch.ingredients : (current?.ingredients ?? null),
      allergens: patch.allergens !== undefined ? patch.allergens : (current?.allergens ?? []),
      nutrition: patch.nutrition !== undefined ? patch.nutrition : (current?.nutrition ?? null),
      nutritionSource:
        patch.nutritionSource !== undefined
          ? patch.nutritionSource
          : (current?.nutritionSource ?? null),
      isOrganic: patch.isOrganic !== undefined ? patch.isOrganic : (current?.isOrganic ?? false),
      organicCertification:
        patch.organicCertification !== undefined
          ? patch.organicCertification
          : (current?.organicCertification ?? null),
    };

    const result = await this.pool.query<RichDataRow>(
      `INSERT INTO catalog_product_rich_data
         (product_id, ingredients, allergens, nutrition, nutrition_source, is_organic, organic_certification)
       VALUES ($1, $2, $3, $4, $5, $6, $7)
       ON CONFLICT (product_id) DO UPDATE SET
         ingredients = EXCLUDED.ingredients,
         allergens = EXCLUDED.allergens,
         nutrition = EXCLUDED.nutrition,
         nutrition_source = EXCLUDED.nutrition_source,
         is_organic = EXCLUDED.is_organic,
         organic_certification = EXCLUDED.organic_certification,
         updated_at = now()
       RETURNING *`,
      [
        productId,
        next.ingredients,
        next.allergens,
        next.nutrition,
        next.nutritionSource,
        next.isOrganic,
        next.organicCertification,
      ],
    );
    const row = result.rows[0];
    if (!row) {
      throw new Error('catalog_product_rich_data UPSERT returned no row');
    }
    return toRichData(row);
  }
}

function toRichData(row: RichDataRow): ProductRichData {
  return {
    productId: row.product_id,
    ingredients: row.ingredients,
    allergens: row.allergens,
    nutrition: row.nutrition,
    nutritionSource: row.nutrition_source,
    isOrganic: row.is_organic,
    organicCertification: row.organic_certification,
    createdAt: row.created_at,
    updatedAt: row.updated_at,
  };
}
