import { Injectable, Inject } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import { WhmcsConnectionOrchestratorService } from "../connection/services/whmcs-connection-orchestrator.service";
import { getErrorMessage } from "@bff/core/utils/error.util";
import { WhmcsOperationException } from "@bff/core/exceptions/domain-exceptions";

import type {
  WhmcsOrderItem,
  WhmcsAddOrderParams,
  WhmcsAddOrderResponse,
  WhmcsOrderResult,
} from "@customer-portal/domain/orders";
import {
  Providers,
  whmcsAddOrderResponseSchema,
  whmcsAcceptOrderResponseSchema,
} from "@customer-portal/domain/orders";

export type { WhmcsOrderItem, WhmcsAddOrderParams, WhmcsOrderResult };

@Injectable()
export class WhmcsOrderService {
  constructor(
    private readonly connection: WhmcsConnectionOrchestratorService,
    @Inject(Logger) private readonly logger: Logger
  ) {}

  /**
   * Create order in WHMCS using AddOrder API
   * Maps Salesforce OrderItems to WHMCS products
   *
   * WHMCS API Response Structure:
   * Success: { orderid, productids, serviceids, addonids, domainids, invoiceid }
   * Error: Thrown by HTTP client before returning
   */
  async addOrder(params: WhmcsAddOrderParams): Promise<WhmcsOrderResult> {
    this.logger.log("Creating WHMCS order", {
      clientId: params.clientId,
      itemCount: params.items.length,
      sfOrderId: params.sfOrderId,
      hasPromoCode: Boolean(params.promoCode),
    });

    try {
      // Build WHMCS AddOrder payload
      const addOrderPayload = this.buildAddOrderPayload(params);

      this.logger.debug("Built WHMCS AddOrder payload", {
        clientId: params.clientId,
        productCount: Array.isArray(addOrderPayload.pid) ? addOrderPayload.pid.length : 0,
        pids: addOrderPayload.pid,
        quantities: addOrderPayload.qty, // CRITICAL: Must be included for products to be added
        billingCycles: addOrderPayload.billingcycle,
        hasConfigOptions: Boolean(addOrderPayload.configoptions),
        hasCustomFields: Boolean(addOrderPayload.customfields),
        promoCode: addOrderPayload.promocode,
        paymentMethod: addOrderPayload.paymentmethod,
      });

      // Call WHMCS AddOrder API
      // Note: The HTTP client throws errors automatically if result === "error"
      // So we only get here if the request was successful
      const response = (await this.connection.addOrder(addOrderPayload)) as WhmcsAddOrderResponse;

      // Log the full response for debugging
      this.logger.debug("WHMCS AddOrder response", {
        response,
        clientId: params.clientId,
        sfOrderId: params.sfOrderId,
      });

      const parsedResponse = whmcsAddOrderResponseSchema.safeParse(response);
      if (!parsedResponse.success) {
        this.logger.error("WHMCS AddOrder response failed validation", {
          clientId: params.clientId,
          sfOrderId: params.sfOrderId,
          issues: parsedResponse.error.flatten(),
          rawResponse: response,
        });
        throw new WhmcsOperationException("WHMCS AddOrder response was invalid", {
          response,
        });
      }

      const normalizedResult = this.toWhmcsOrderResult(parsedResponse.data);

      this.logger.log("WHMCS order created successfully", {
        orderId: normalizedResult.orderId,
        invoiceId: normalizedResult.invoiceId,
        serviceIds: normalizedResult.serviceIds,
        addonIds: normalizedResult.addonIds,
        domainIds: normalizedResult.domainIds,
        clientId: params.clientId,
        sfOrderId: params.sfOrderId,
      });

      return normalizedResult;
    } catch (error) {
      // Enhanced error logging with full context
      this.logger.error("Failed to create WHMCS order", {
        error: getErrorMessage(error),
        errorType: error?.constructor?.name,
        clientId: params.clientId,
        sfOrderId: params.sfOrderId,
        itemCount: params.items.length,
        // Include first 100 chars of error stack for debugging
        errorStack: error instanceof Error ? error.stack?.substring(0, 100) : undefined,
      });
      throw error;
    }
  }

  /**
   * Accept/provision order in WHMCS using AcceptOrder API
   * This activates services and creates subscriptions
   *
   * WHMCS API Response Structure:
   * Success: { orderid, invoiceid, serviceids, addonids, domainids }
   * Error: Thrown by HTTP client before returning
   */
  async acceptOrder(orderId: number, sfOrderId?: string): Promise<void> {
    this.logger.log("Accepting WHMCS order", {
      orderId,
      sfOrderId,
    });

    try {
      // Call WHMCS AcceptOrder API
      // Note: The HTTP client throws errors automatically if result === "error"
      // So we only get here if the request was successful
      const response = (await this.connection.acceptOrder(orderId)) as Record<string, unknown>;

      // Log the full response for debugging
      this.logger.debug("WHMCS AcceptOrder response", {
        response,
        orderId,
        sfOrderId,
      });

      const parsedResponse = whmcsAcceptOrderResponseSchema.safeParse(response);
      if (!parsedResponse.success) {
        this.logger.error("WHMCS AcceptOrder response failed validation", {
          orderId,
          sfOrderId,
          issues: parsedResponse.error.flatten(),
          rawResponse: response,
        });
        throw new WhmcsOperationException("WHMCS AcceptOrder response was invalid", {
          response,
        });
      }

      this.logger.log("WHMCS order accepted successfully", {
        orderId,
        invoiceId: parsedResponse.data.invoiceid,
        sfOrderId,
      });
    } catch (error) {
      // Enhanced error logging with full context
      this.logger.error("Failed to accept WHMCS order", {
        error: getErrorMessage(error),
        errorType: error?.constructor?.name,
        orderId,
        sfOrderId,
        // Include first 100 chars of error stack for debugging
        errorStack: error instanceof Error ? error.stack?.substring(0, 100) : undefined,
      });
      throw error;
    }
  }

  /**
   * Get order details from WHMCS
   */
  async getOrderDetails(orderId: number): Promise<Record<string, unknown> | null> {
    try {
      // Note: The HTTP client throws errors automatically if result === "error"
      const response = (await this.connection.getOrders({
        id: orderId.toString(),
      })) as Record<string, unknown>;

      return (response.orders as { order?: Record<string, unknown>[] })?.order?.[0] || null;
    } catch (error) {
      this.logger.error("Failed to get WHMCS order details", {
        error: getErrorMessage(error),
        errorType: error?.constructor?.name,
        orderId,
      });
      throw error;
    }
  }

  /**
   * Check if client has valid payment method
   */
  async hasPaymentMethod(clientId: number): Promise<boolean> {
    try {
      const response = await this.connection.getPaymentMethods({
        clientid: clientId,
      });

      const methods = Array.isArray(response.paymethods) ? response.paymethods : [];
      const hasValidMethod = methods.length > 0;

      this.logger.log("Payment method check completed", {
        clientId,
        hasPaymentMethod: hasValidMethod,
        methodCount: methods.length,
      });

      return hasValidMethod;
    } catch (error) {
      this.logger.error("Failed to check payment methods", {
        error: getErrorMessage(error),
        clientId,
      });
      // Don't throw - return false to indicate no payment method
      return false;
    }
  }

  /**
   * Build WHMCS AddOrder payload from our parameters
   * Following official WHMCS API documentation format
   *
   * Delegates to shared mapper function from integration package
   */
  private buildAddOrderPayload(params: WhmcsAddOrderParams): Record<string, unknown> {
    const payload = Providers.Whmcs.buildWhmcsAddOrderPayload(params);

    this.logger.debug("Built WHMCS AddOrder payload", {
      clientId: params.clientId,
      productCount: params.items.length,
      pids: payload.pid,
      billingCycles: payload.billingcycle,
      hasConfigOptions: !!payload.configoptions,
      hasCustomFields: !!payload.customfields,
    });

    return payload as Record<string, unknown>;
  }

  private toWhmcsOrderResult(response: WhmcsAddOrderResponse): WhmcsOrderResult {
    const orderId = parseInt(String(response.orderid), 10);
    if (!orderId || Number.isNaN(orderId)) {
      throw new WhmcsOperationException("WHMCS AddOrder did not return valid order ID", {
        response,
      });
    }

    return {
      orderId,
      invoiceId: response.invoiceid ? parseInt(String(response.invoiceid), 10) : undefined,
      serviceIds: this.parseDelimitedIds(response.serviceids),
      addonIds: this.parseDelimitedIds(response.addonids),
      domainIds: this.parseDelimitedIds(response.domainids),
    };
  }

  private parseDelimitedIds(value?: string): number[] {
    if (!value) {
      return [];
    }
    return value
      .toString()
      .split(",")
      .map(entry => parseInt(entry.trim(), 10))
      .filter(id => !Number.isNaN(id));
  }
}
