import type {
  ProductRepository,
  ProductRichDataRepository,
  ProductVariantRepository,
} from '../domain/ports.js';
import type { PricingServicePort } from '../../pricing/index.js';
import type {
  NewProductVariant,
  ProductRichData,
  ProductVariant,
  ProductVariantPatch,
  RichDataPatch,
} from '../domain/variant.js';

export class ListProductVariants {
  constructor(private readonly variants: ProductVariantRepository) {}

  async execute(productId: string): Promise<ProductVariant[]> {
    return this.variants.listByProductId(productId);
  }
}

export class CreateProductVariant {
  constructor(
    private readonly products: ProductRepository,
    private readonly variants: ProductVariantRepository,
    private readonly pricing: PricingServicePort,
  ) {}

  async execute(productId: string, input: NewProductVariant): Promise<ProductVariant | undefined> {
    if (!(await this.products.findById(productId))) {
      return undefined;
    }
    const variant = await this.variants.create(productId, input);
    // Best-effort: seed a default price row immediately so GET /pricing/variants/:id
    // never 404s after variant creation (F-138). The variant already persisted, so a
    // seed failure must not fail or roll back variant creation itself.
    try {
      await this.pricing.seedVariantPrice(variant.id);
    } catch (error) {
      void error;
    }
    return variant;
  }
}

export class UpdateProductVariant {
  constructor(private readonly variants: ProductVariantRepository) {}

  async execute(
    productId: string,
    variantId: string,
    patch: ProductVariantPatch,
  ): Promise<ProductVariant | undefined> {
    return this.variants.update(productId, variantId, patch);
  }
}

export class UpsertProductRichData {
  constructor(
    private readonly products: ProductRepository,
    private readonly richData: ProductRichDataRepository,
  ) {}

  async execute(productId: string, patch: RichDataPatch): Promise<ProductRichData | undefined> {
    if (!(await this.products.findById(productId))) {
      return undefined;
    }
    const current = await this.richData.findByProductId(productId);
    const protectedPatch = protectManualNutrition(current, patch);
    return this.richData.upsert(productId, protectedPatch);
  }
}

export function protectManualNutrition(
  current: ProductRichData | undefined,
  patch: RichDataPatch,
): RichDataPatch {
  if (
    current?.nutritionSource === 'manual' &&
    patch.nutrition !== undefined &&
    patch.nutritionSource !== undefined &&
    patch.nutritionSource !== 'manual'
  ) {
    const { nutrition: _nutrition, nutritionSource: _nutritionSource, ...rest } = patch;
    return rest;
  }
  return patch;
}
