import { Injectable, BadRequestException, Inject } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import {
  OrderPricebookService,
  type PricebookProductMeta,
} from "../services/order-pricebook.service.js";
import {
  ValidationErrorCode,
  createValidationError,
  validationFailure,
  validationSuccess,
  type ValidationResult,
} from "./base-validator.interface.js";

/**
 * SKU Validator
 *
 * Validates that product SKUs exist in the Salesforce pricebook.
 */
@Injectable()
export class SkuValidator {
  constructor(
    @Inject(Logger) private readonly logger: Logger,
    private readonly pricebookService: OrderPricebookService
  ) {}

  /**
   * Validate SKUs exist in Salesforce pricebook
   * Returns validation result with product metadata on success
   */
  async validate(
    skus: string[],
    pricebookId: string
  ): Promise<ValidationResult<Map<string, PricebookProductMeta>>> {
    const meta = await this.pricebookService.fetchProductMeta(pricebookId, skus);
    const invalidSKUs: string[] = [];

    const normalizedSkus = skus
      .map(sku => sku?.trim())
      .filter((sku): sku is string => Boolean(sku))
      .map(sku => ({ raw: sku, normalized: sku.toUpperCase() }));

    for (const sku of normalizedSkus) {
      if (!meta.has(sku.normalized)) {
        invalidSKUs.push(sku.raw);
      }
    }

    if (invalidSKUs.length > 0) {
      this.logger.error({ invalidSKUs }, "Invalid SKUs found in order");
      return validationFailure([
        createValidationError(
          ValidationErrorCode.INVALID_SKU,
          `Invalid products: ${invalidSKUs.join(", ")}`,
          "skus"
        ),
      ]);
    }

    return validationSuccess(meta);
  }

  /**
   * Validate and throw BadRequestException on failure
   */
  async validateOrThrow(
    skus: string[],
    pricebookId: string
  ): Promise<Map<string, PricebookProductMeta>> {
    const result = await this.validate(skus, pricebookId);

    if (!result.success) {
      const error = result.errors?.[0];
      throw new BadRequestException(error?.message ?? "SKU validation failed");
    }

    return result.data!;
  }

  /**
   * Get the portal pricebook ID
   */
  async getPricebookId(): Promise<string> {
    return this.pricebookService.findPortalPricebookId();
  }
}
