import { Customer } from '@isa/crm/data-access';
import { ShippingAddress as CrmShippingAddress } from '@isa/crm/data-access';
import { ShippingAddress as CheckoutShippingAddress } from '@isa/checkout/data-access';

/**
 * Adapter for converting CRM shipping address data to checkout-api format.
 *
 * Handles two distinct conversion scenarios:
 * 1. **Separate Shipping Address Entity** (`fromCrmShippingAddress`): Converts a dedicated
 *    shipping address from CRM with `source` field, indicating a persistent entity.
 * 2. **Customer Primary Address** (`fromCustomer`): Derives shipping address from customer's
 *    primary address without `source` field, indicating transient/derived data.
 *
 * **Key Differences:**
 * - CRM ShippingAddressDTO: Filters out CRM-specific fields (type, validated, agentComment, etc.)
 * - Customer Address: Uses customer ID for reference, omits `source` field
 */
export class ShippingAddressAdapter {
  private static readonly ADAPTER_NAME = 'ShippingAddressAdapter';

  /**
   * Converts CRM-api ShippingAddressDTO to checkout-api format.
   *
   * @remarks
   * Used when customer has separate delivery addresses stored in `customer.shippingAddresses[]`.
   * The resulting address includes a `source` field, indicating it references a persistent
   * shipping address entity in the CRM system.
   *
   * Filters out CRM-specific fields:
   * - `type` (ShippingAddressType)
   * - `validated` (validation flag)
   * - `validationResult` (validation status code)
   * - `agentComment` (internal notes)
   * - `isDefault` (default address flag)
   *
   * @param address - Raw shipping address from CRM service (optional)
   * @returns ShippingAddressDTO compatible with checkout-api, includes `source` field, or undefined if address is not provided
   *
   * @example
   * ```typescript
   * const crmAddress = customer.shippingAddresses[0].data;
   * const checkoutAddress = ShippingAddressAdapter.fromCrmShippingAddress(crmAddress);
   * await checkoutService.complete({ shippingAddress: checkoutAddress, ... });
   * ```
   */
  static fromCrmShippingAddress(
    address: CrmShippingAddress | undefined,
  ): CheckoutShippingAddress | undefined {
    if (!address) {
      return undefined;
    }

    return {
      reference: { id: address.id },
      gender: address.gender,
      title: address.title,
      firstName: address.firstName,
      lastName: address.lastName,
      communicationDetails: address.communicationDetails
        ? { ...address.communicationDetails }
        : undefined,
      organisation: address.organisation
        ? { ...address.organisation }
        : undefined,
      address: address.address
        ? {
            street: address.address.street,
            streetNumber: address.address.streetNumber,
            zipCode: address.address.zipCode,
            city: address.address.city,
            country: address.address.country,
          }
        : undefined,
      source: address.id,
    };
  }

  /**
   * Converts Customer to checkout-api ShippingAddressDTO.
   *
   * @remarks
   * Used when customer's primary address is used for shipping (e.g., B2B customers, staff,
   * customer card holders without separate delivery addresses).
   *
   * The resulting address **does not include** a `source` field, indicating this is derived
   * from the customer entity and not a separate persistent shipping address entity.
   *
   * Uses customer's primary address data (`customer.address`) and personal information.
   *
   * @param customer - Customer from CRM service
   * @returns ShippingAddressDTO compatible with checkout-api, omits `source` field
   *
   * @example
   * ```typescript
   * const customer = await crmService.getCustomer(123);
   * const checkoutAddress = ShippingAddressAdapter.fromCustomer(customer);
   * await checkoutService.complete({ shippingAddress: checkoutAddress, ... });
   * ```
   */
  static fromCustomer(customer: Customer): CheckoutShippingAddress {
    return {
      reference: { id: customer.id },
      gender: customer.gender,
      title: customer.title,
      firstName: customer.firstName,
      lastName: customer.lastName,
      communicationDetails: customer.communicationDetails
        ? { ...customer.communicationDetails }
        : undefined,
      organisation: customer.organisation
        ? { ...customer.organisation }
        : undefined,
      address: customer.address
        ? {
            street: customer.address.street,
            streetNumber: customer.address.streetNumber,
            zipCode: customer.address.zipCode,
            city: customer.address.city,
            country: customer.address.country,
          }
        : undefined,
    };
  }

  /**
   * Type guard for CRM shipping address response
   *
   * @param value - Value to check
   * @returns true if value is a valid CRM shipping address with required fields
   */
  static isValidCrmShippingAddress(
    value: unknown,
  ): value is CrmShippingAddress {
    if (typeof value !== 'object' || value === null) return false;

    const address = value as CrmShippingAddress;
    return typeof address.id === 'number';
  }

  /**
   * Type guard for Customer
   *
   * @param value - Value to check
   * @returns true if value is a valid Customer with required fields
   */
  static isValidCustomer(value: unknown): value is Customer {
    if (typeof value !== 'object' || value === null) return false;

    const customer = value as Customer;
    return (
      typeof customer.id === 'number' &&
      (customer.customerNumber === undefined ||
        typeof customer.customerNumber === 'string')
    );
  }
}
