import { Injectable, BadRequestException, NotFoundException, Inject } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import { OrderPricebookService } from "./order-pricebook.service";
import { createOrderRequestSchema } from "@customer-portal/domain/orders";

/**
 * Handles building order items from SKU data
 */
@Injectable()
export class OrderItemBuilder {
  constructor(
    @Inject(Logger) private readonly logger: Logger,
    private readonly pricebookService: OrderPricebookService
  ) {}

  /**
   * Prepare OrderItems for Salesforce composite tree creation
   */
  async buildOrderItemsPayload(
    skus: string[],
    pricebookId: string
  ): Promise<OrderItemCompositePayload[]> {
    const { skus: validatedSkus } = buildItemsSchema.parse({ skus });
    if (pricebookId.length === 0) {
      throw new BadRequestException("Product SKU is required");
    }

    this.logger.log({ skus }, "Preparing OrderItems payload from SKU array");

    const metaMap = await this.pricebookService.fetchProductMeta(pricebookId, skus);

    const payload: OrderItemCompositePayload[] = [];

    for (const sku of validatedSkus) {
      const normalizedSkuValue = sku?.trim();
      if (!normalizedSkuValue) {
        this.logger.error("Encountered empty SKU while preparing order items payload");
        throw new BadRequestException("Product SKU is required");
      }

      const normalizedSku = normalizedSkuValue.toUpperCase();
      const meta = metaMap.get(normalizedSku);

      if (!meta?.pricebookEntryId) {
        this.logger.error({ sku }, "PricebookEntry not found for SKU");
        throw new NotFoundException(`Product not found: ${sku}`);
      }

      if (!meta.unitPrice) {
        this.logger.error(
          { sku: normalizedSkuValue, pbeId: meta.pricebookEntryId },
          "PricebookEntry missing UnitPrice"
        );
        throw new Error(`PricebookEntry for SKU ${normalizedSkuValue} has no UnitPrice set`);
      }

      payload.push({
        sku: normalizedSkuValue,
        pricebookEntryId: meta.pricebookEntryId,
        quantity: 1,
        unitPrice: meta.unitPrice,
      });
    }

    this.logger.log(
      { itemCount: payload.length, skus: payload.map(item => item.sku) },
      "Prepared OrderItems payload"
    );

    return payload;
  }

  /**
   * Get service product metadata from SKU array for order header defaults
   */
  async getServiceProductMetaFromSKUs(skus: string[], pricebookId: string) {
    // Find main service SKU (usually first, or contains service indicators)
    const serviceSku =
      skus.find(
        sku =>
          !sku.toUpperCase().includes("INSTALL") &&
          !sku.toUpperCase().includes("ACTIVATION") &&
          !sku.toUpperCase().includes("ADDON")
      ) || skus[0];

    // Find installation SKU
    const installSku = skus.find(sku => sku.toUpperCase().includes("INSTALL"));

    const targets = [serviceSku, installSku].filter(
      (sku): sku is string => typeof sku === "string" && sku.length > 0
    );
    const metaMap = await this.pricebookService.fetchProductMeta(pricebookId, targets);

    const mapMeta = (sku?: string | null) => {
      if (!sku) return null;
      const entry = metaMap.get(sku.trim().toUpperCase());
      if (!entry) return null;
      return {
        pbeId: entry.pricebookEntryId,
        product2Id: entry.product2Id ?? "",
        unitPrice: entry.unitPrice,
        itemClass: entry.itemClass,
        internetOfferingType: entry.internetOfferingType,
        internetPlanTier: entry.internetPlanTier,
        vpnRegion: entry.vpnRegion,
      };
    };

    return {
      serviceProduct: mapMeta(serviceSku),
      installProduct: mapMeta(installSku),
    };
  }
}

export interface OrderItemCompositePayload {
  sku: string;
  pricebookEntryId: string;
  quantity: number;
  unitPrice: number;
}

const buildItemsSchema = createOrderRequestSchema.pick({ skus: true });
