import { Injectable, Inject } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import type { OrderBusinessValidation, UserMapping } from "@customer-portal/domain/orders";
import { UsersFacade } from "@bff/modules/users/application/users.facade";
import { OrderFieldMapService } from "@bff/modules/orders/config/order-field-map.service";

function assignIfString(target: Record<string, unknown>, key: string, value: unknown): void {
  if (typeof value === "string" && value.trim().length > 0) {
    target[key] = value;
  }
}

/**
 * Builds Salesforce Order records from domain order requests
 */
@Injectable()
export class OrderBuilder {
  constructor(
    @Inject(Logger) private readonly logger: Logger,
    private readonly usersFacade: UsersFacade,
    private readonly orderFieldMap: OrderFieldMapService
  ) {}

  async buildOrderFields(
    body: OrderBusinessValidation,
    userMapping: UserMapping,
    pricebookId: string,
    userId: string
  ): Promise<Record<string, unknown>> {
    const today = new Date().toISOString().slice(0, 10);
    const orderFieldNames = this.orderFieldMap.fields.order;

    const orderFields: Record<string, unknown> = {
      AccountId: userMapping.sfAccountId,
      EffectiveDate: today,
      Status: "Pending Review",
      Pricebook2Id: pricebookId,
      [orderFieldNames.type]: body.orderType,
      ...(body.opportunityId ? { OpportunityId: body.opportunityId } : {}),
    };

    this.addActivationFields(orderFields, body, orderFieldNames);

    switch (body.orderType) {
      case "Internet":
        this.addInternetFields(orderFields, body, orderFieldNames);
        break;
      case "SIM":
        this.addSimFields(orderFields, body, orderFieldNames);
        break;
      case "VPN":
        this.addVpnFields(orderFields, body);
        break;
    }

    await this.addAddressSnapshot(orderFields, userId, body, orderFieldNames);

    return orderFields;
  }

  private addActivationFields(
    orderFields: Record<string, unknown>,
    body: OrderBusinessValidation,
    fieldNames: OrderFieldMapService["fields"]["order"]
  ): void {
    const config = body.configurations || {};

    assignIfString(orderFields, fieldNames.activationType, config.activationType);
    assignIfString(orderFields, fieldNames.activationScheduledAt, config.scheduledAt);
    orderFields[fieldNames.activationStatus] = "Not Started";
  }

  private addInternetFields(
    orderFields: Record<string, unknown>,
    body: OrderBusinessValidation,
    fieldNames: OrderFieldMapService["fields"]["order"]
  ): void {
    const config = body.configurations || {};
    assignIfString(orderFields, fieldNames.accessMode, config.accessMode);
  }

  private addSimFields(
    orderFields: Record<string, unknown>,
    body: OrderBusinessValidation,
    fieldNames: OrderFieldMapService["fields"]["order"]
  ): void {
    const config = body.configurations || {};
    assignIfString(orderFields, fieldNames.simType, config.simType);
    assignIfString(orderFields, fieldNames.eid, config.eid);

    if (config.isMnp === "true") {
      orderFields[fieldNames.mnpApplication] = true;
      assignIfString(orderFields, fieldNames.mnpReservation, config.mnpNumber);
      assignIfString(orderFields, fieldNames.mnpExpiry, config.mnpExpiry);
      assignIfString(orderFields, fieldNames.mnpPhone, config.mnpPhone);
      assignIfString(orderFields, fieldNames.mvnoAccountNumber, config.mvnoAccountNumber);
      assignIfString(orderFields, fieldNames.portingLastName, config.portingLastName);
      assignIfString(orderFields, fieldNames.portingFirstName, config.portingFirstName);
      assignIfString(
        orderFields,
        fieldNames.portingLastNameKatakana,
        config.portingLastNameKatakana
      );
      assignIfString(
        orderFields,
        fieldNames.portingFirstNameKatakana,
        config.portingFirstNameKatakana
      );
      assignIfString(orderFields, fieldNames.portingGender, config.portingGender);
      assignIfString(orderFields, fieldNames.portingDateOfBirth, config.portingDateOfBirth);
    }
  }

  private addVpnFields(
    _orderFields: Record<string, unknown>,
    _body: OrderBusinessValidation
  ): void {
    // No additional fields for VPN orders at this time.
  }

  private async addAddressSnapshot(
    orderFields: Record<string, unknown>,
    userId: string,
    body: OrderBusinessValidation,
    fieldNames: OrderFieldMapService["fields"]["order"]
  ): Promise<void> {
    try {
      const profile = await this.usersFacade.getProfile(userId);
      const address = profile.address;
      const orderAddress = (body.configurations as Record<string, unknown>)?.address as
        | Record<string, unknown>
        | undefined;
      const addressChanged = !!orderAddress;
      const addressToUse = orderAddress || address;
      const address1 = typeof addressToUse?.address1 === "string" ? addressToUse.address1 : "";
      const address2 = typeof addressToUse?.address2 === "string" ? addressToUse.address2 : "";
      const fullStreet = [address1, address2].filter(Boolean).join(", ");

      orderFields[fieldNames.billingStreet] = fullStreet;
      orderFields[fieldNames.billingCity] =
        typeof addressToUse?.city === "string" ? addressToUse.city : "";
      orderFields[fieldNames.billingState] =
        typeof addressToUse?.state === "string" ? addressToUse.state : "";
      orderFields[fieldNames.billingPostalCode] =
        typeof addressToUse?.postcode === "string" ? addressToUse.postcode : "";
      orderFields[fieldNames.billingCountry] =
        typeof addressToUse?.country === "string" ? addressToUse.country : "";
      orderFields[fieldNames.addressChanged] = addressChanged;

      if (addressChanged) {
        this.logger.log({ userId }, "Customer updated address during checkout");
      }

      this.logger.debug(
        {
          userId,
          hasAddress: !!address1,
          addressChanged,
        },
        "Address snapshot added to order"
      );
    } catch (error) {
      this.logger.warn(
        {
          userId,
          error: error instanceof Error ? error.message : String(error),
        },
        "Failed to add address snapshot"
      );
    }
  }
}
