import { Injectable } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import {
  createSalesforceOrderFieldMap,
  defaultSalesforceOrderFieldMap,
  type PartialSalesforceOrderFieldMap,
  type SalesforceOrderFieldMap,
} from "@customer-portal/domain/orders";

const unique = <T>(values: T[]): T[] => Array.from(new Set(values));

const SECTION_PREFIX: Record<keyof SalesforceOrderFieldMap, string> = {
  order: "ORDER",
  orderItem: "ORDER_ITEM",
  product: "PRODUCT",
};

@Injectable()
export class OrderFieldMapService {
  readonly fields: SalesforceOrderFieldMap;

  constructor(private readonly config: ConfigService) {
    const overrides: PartialSalesforceOrderFieldMap = {
      order: this.resolveSection("order"),
      orderItem: this.resolveSection("orderItem"),
      product: this.resolveSection("product"),
    };

    this.fields = createSalesforceOrderFieldMap(overrides);
  }

  buildOrderSelectFields(additional: string[] = []): string[] {
    const { order } = this.fields;
    const base = [
      "Id",
      "AccountId",
      "Status",
      order.type,
      "EffectiveDate",
      "OrderNumber",
      "TotalAmount",
      "CreatedDate",
      "LastModifiedDate",
      "Pricebook2Id",
      order.activationType,
      order.activationStatus,
      order.activationScheduledAt,
      order.activationErrorCode,
      order.activationErrorMessage,
      order.activationLastAttemptAt,
      order.internetPlanTier,
      order.installationType,
      order.accessMode,
      order.weekendInstall,
      order.hikariDenwa,
      order.vpnRegion,
      order.simType,
      order.simVoiceMail,
      order.simCallWaiting,
      order.eid,
      order.whmcsOrderId,
      order.addressChanged,
      order.billingStreet,
      order.billingCity,
      order.billingState,
      order.billingPostalCode,
      order.billingCountry,
    ];

    return unique([...base, ...additional]);
  }

  buildOrderItemSelectFields(additional: string[] = []): string[] {
    const { orderItem } = this.fields;
    const base = [
      "Id",
      "OrderId",
      "Quantity",
      "UnitPrice",
      "TotalPrice",
      "PricebookEntry.Id",
      orderItem.whmcsServiceId,
    ];

    return unique([...base, ...additional]);
  }

  buildOrderItemProduct2Fields(additional: string[] = []): string[] {
    const { product } = this.fields;
    const base = [
      "Id",
      "Name",
      product.sku,
      product.itemClass,
      product.billingCycle,
      product.whmcsProductId,
      product.internetOfferingType,
      product.internetPlanTier,
      product.vpnRegion,
      product.bundledAddon,
      product.isBundledAddon,
    ];

    return unique([...base, ...additional]);
  }

  private resolveSection<Section extends keyof SalesforceOrderFieldMap>(
    section: Section
  ): Partial<SalesforceOrderFieldMap[Section]> {
    const defaults = defaultSalesforceOrderFieldMap[section];
    const resolvedEntries = Object.entries(defaults).map(([key, defaultValue]) => {
      const envKey = buildEnvKey(section, key);
      const resolved = this.config.get<string>(envKey, { infer: true });
      return [key, resolved ?? defaultValue];
    });

    return Object.fromEntries(resolvedEntries) as Partial<SalesforceOrderFieldMap[Section]>;
  }
}

function buildEnvKey<Section extends keyof SalesforceOrderFieldMap>(
  section: Section,
  key: string
): string {
  const prefix = SECTION_PREFIX[section];
  return `${prefix}_${toScreamingSnakeCase(key)}_FIELD`;
}

function toScreamingSnakeCase(value: string): string {
  return value
    .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
    .replace(/[-\s]+/g, "_")
    .toUpperCase();
}
