import { Injectable, Inject } from "@nestjs/common";
import type { OnModuleInit } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import { extractErrorMessage } from "@bff/core/utils/error.util.js";
import { WhmcsConfigService } from "../connection/config/whmcs-config.service.js";
import { WhmcsHttpClientService } from "../connection/services/whmcs-http-client.service.js";
import { WhmcsErrorHandlerService } from "../connection/services/whmcs-error-handler.service.js";
import { WhmcsRequestQueueService } from "@bff/infra/queue/services/whmcs-request-queue.service.js";
import type {
  WhmcsAddClientParams,
  WhmcsValidateLoginParams,
  WhmcsCreateSsoTokenParams,
  WhmcsClientResponse,
  WhmcsAddClientResponse,
  WhmcsValidateLoginResponse,
  WhmcsSsoResponse,
  WhmcsGetUsersResponse,
} from "@customer-portal/domain/customer/providers";
import type {
  WhmcsGetInvoicesParams,
  WhmcsCreateInvoiceParams,
  WhmcsUpdateInvoiceParams,
  WhmcsCapturePaymentParams,
  WhmcsInvoiceListResponse,
  WhmcsInvoiceResponse,
  WhmcsCreateInvoiceResponse,
  WhmcsUpdateInvoiceResponse,
  WhmcsCapturePaymentResponse,
} from "@customer-portal/domain/billing/providers";
import type {
  WhmcsGetPayMethodsParams,
  WhmcsPaymentMethodListResponse,
  WhmcsPaymentGatewayListResponse,
} from "@customer-portal/domain/payments/providers";
import type {
  WhmcsGetClientsProductsParams,
  WhmcsProductListResponse,
} from "@customer-portal/domain/subscriptions/providers";
import type { WhmcsCatalogProductListResponse } from "@customer-portal/domain/services/providers";
import type { WhmcsAddOrderPayload } from "@customer-portal/domain/orders/providers";
import type { WhmcsErrorResponse } from "@customer-portal/domain/common/providers";
import type {
  WhmcsRequestOptions,
  WhmcsConnectionStats,
} from "../connection/types/connection.types.js";

/**
 * Parameters for WHMCS UpdateClient API.
 * Any client field can be updated; these are the most common ones.
 */
interface WhmcsUpdateClientParams {
  firstname?: string | undefined;
  lastname?: string | undefined;
  companyname?: string | undefined;
  email?: string | undefined;
  address1?: string | undefined;
  address2?: string | undefined;
  city?: string | undefined;
  state?: string | undefined;
  postcode?: string | undefined;
  country?: string | undefined;
  phonenumber?: string | undefined;
  currency?: string | number | undefined;
  language?: string | undefined;
  status?: string | undefined;
  notes?: string | undefined;
  [key: string]: unknown;
}

/**
 * Parameters for WHMCS GetOrders API.
 */
interface WhmcsGetOrdersParams {
  id?: string;
  userid?: number;
  status?: string;
  limitstart?: number;
  limitnum?: number;
  [key: string]: unknown;
}

/**
 * WHMCS Connection Facade
 *
 * Single entry point for all WHMCS API operations.
 * Provides unified interface with queue management, error handling, and request prioritization.
 *
 * @remarks
 * All WHMCS entity services (Invoice, Client, Subscription, etc.) delegate to this facade
 * for actual API communication. This ensures consistent error handling and rate limiting.
 */
@Injectable()
export class WhmcsConnectionFacade implements OnModuleInit {
  constructor(
    @Inject(Logger) private readonly logger: Logger,
    private readonly configService: WhmcsConfigService,
    private readonly httpClient: WhmcsHttpClientService,
    private readonly errorHandler: WhmcsErrorHandlerService,
    private readonly requestQueue: WhmcsRequestQueueService
  ) {}

  async onModuleInit() {
    try {
      // Validate configuration on startup
      this.configService.validateConfig();

      // Test connection
      const isAvailable = await this.isAvailable();
      if (isAvailable) {
        this.logger.log("WHMCS connection established successfully");
      } else {
        this.logger.warn("WHMCS connection test failed - service may be unavailable");
      }
    } catch (error) {
      this.logger.error("Failed to initialize WHMCS connection", {
        error: extractErrorMessage(error),
      });
    }
  }

  // ==========================================
  // CORE REQUEST METHOD
  // ==========================================

  /**
   * Make a request to WHMCS API with full error handling and queue management
   *
   * @param action - WHMCS API action name
   * @param params - Request parameters
   * @param options - Request options including timeout, retries, and priority
   */
  async makeRequest<T>(
    action: string,
    params: Record<string, unknown> = {},
    options: WhmcsRequestOptions = {}
  ): Promise<T> {
    const executeRequest = async (): Promise<T> => {
      try {
        const config = this.configService.getConfig();
        const response = await this.httpClient.makeRequest<T>(config, action, params, options);

        if (response.result === "error") {
          const errorResponse = response as WhmcsErrorResponse;
          this.errorHandler.handleApiError(errorResponse, action);
        }

        return response.data as T;
      } catch (error) {
        // If it's already a handled error, re-throw it
        if (this.isHandledException(error)) {
          throw error;
        }

        // Handle general request errors
        this.errorHandler.handleRequestError(error);
      }
    };

    // High priority requests jump the queue
    if (options.highPriority) {
      return this.requestQueue.executeHighPriority(executeRequest);
    }

    // Normal requests go through the queue with priority
    return this.requestQueue.execute(executeRequest, {
      priority: this.getRequestPriority(action),
      timeout: options.timeout,
      retryAttempts: options.retryAttempts,
      retryDelay: options.retryDelay,
    });
  }

  /**
   * Get queue metrics for monitoring
   */
  getQueueMetrics() {
    return this.requestQueue.getMetrics();
  }

  /**
   * Get queue health status
   */
  getQueueHealth() {
    return this.requestQueue.getHealthStatus();
  }

  // ==========================================
  // HEALTH CHECK METHODS
  // ==========================================

  async healthCheck(): Promise<boolean> {
    try {
      await this.makeRequest("GetProducts", { limitnum: 1 });
      return true;
    } catch {
      return false;
    }
  }

  async isAvailable(): Promise<boolean> {
    return this.healthCheck();
  }

  async getSystemInfo(): Promise<unknown> {
    return this.makeRequest("GetProducts", { limitnum: 1 });
  }

  // ==========================================
  // CLIENT API METHODS
  // ==========================================

  async getClientDetails(clientId: number): Promise<WhmcsClientResponse> {
    return this.makeRequest<WhmcsClientResponse>("GetClientsDetails", {
      clientid: clientId,
      stats: true,
    });
  }

  async getClientDetailsByEmail(email: string): Promise<WhmcsClientResponse> {
    return this.makeRequest<WhmcsClientResponse>("GetClientsDetails", {
      email,
      stats: true,
    });
  }

  async updateClient(
    clientId: number,
    updateData: WhmcsUpdateClientParams
  ): Promise<{ result: string }> {
    return this.makeRequest<{ result: string }>("UpdateClient", {
      clientid: clientId,
      ...updateData,
    });
  }

  async addClient(params: WhmcsAddClientParams): Promise<WhmcsAddClientResponse> {
    return this.makeRequest<WhmcsAddClientResponse>("AddClient", params);
  }

  async validateLogin(params: WhmcsValidateLoginParams): Promise<WhmcsValidateLoginResponse> {
    return this.makeRequest<WhmcsValidateLoginResponse>("ValidateLogin", params);
  }

  /**
   * Get users by email address
   * Used to discover if a user account exists in WHMCS
   */
  async getUsersByEmail(email: string): Promise<WhmcsGetUsersResponse> {
    return this.makeRequest<WhmcsGetUsersResponse>("GetUsers", {
      search: email,
      limitnum: 10,
    });
  }

  // ==========================================
  // INVOICE API METHODS
  // ==========================================

  async getInvoices(params: WhmcsGetInvoicesParams = {}): Promise<WhmcsInvoiceListResponse> {
    return this.makeRequest<WhmcsInvoiceListResponse>("GetInvoices", params);
  }

  async getInvoice(invoiceId: number): Promise<WhmcsInvoiceResponse> {
    return this.makeRequest<WhmcsInvoiceResponse>("GetInvoice", { invoiceid: invoiceId });
  }

  async createInvoice(params: WhmcsCreateInvoiceParams): Promise<WhmcsCreateInvoiceResponse> {
    return this.makeRequest<WhmcsCreateInvoiceResponse>("CreateInvoice", params);
  }

  async updateInvoice(params: WhmcsUpdateInvoiceParams): Promise<WhmcsUpdateInvoiceResponse> {
    return this.makeRequest<WhmcsUpdateInvoiceResponse>("UpdateInvoice", params);
  }

  async capturePayment(params: WhmcsCapturePaymentParams): Promise<WhmcsCapturePaymentResponse> {
    return this.makeRequest<WhmcsCapturePaymentResponse>("CapturePayment", params);
  }

  // ==========================================
  // ORDER OPERATIONS (Used by order services)
  // ==========================================

  async addOrder(params: WhmcsAddOrderPayload) {
    return this.makeRequest("AddOrder", params);
  }

  async getOrders(params: WhmcsGetOrdersParams = {}) {
    return this.makeRequest("GetOrders", params);
  }

  // ==========================================
  // ADMIN OPERATIONS (Used by order services)
  // ==========================================

  /**
   * Accept an order (requires admin authentication)
   */
  async acceptOrder(orderId: number): Promise<{ result: string }> {
    return this.makeRequest<{ result: string }>("AcceptOrder", {
      orderid: orderId.toString(),
      autosetup: true,
      sendemail: false,
    });
  }

  async cancelOrder(orderId: number): Promise<{ result: string }> {
    return this.makeRequest<{ result: string }>("CancelOrder", { orderid: orderId });
  }

  // ==========================================
  // PRODUCT/SUBSCRIPTION API METHODS
  // ==========================================

  async getClientsProducts(
    params: WhmcsGetClientsProductsParams
  ): Promise<WhmcsProductListResponse> {
    return this.makeRequest<WhmcsProductListResponse>("GetClientsProducts", params);
  }

  async getCatalogProducts(): Promise<WhmcsCatalogProductListResponse> {
    return this.makeRequest<WhmcsCatalogProductListResponse>("GetProducts", {});
  }

  async getProducts() {
    return this.makeRequest("GetProducts", {});
  }

  async getCurrencies() {
    return this.makeRequest("GetCurrencies", {});
  }

  // ==========================================
  // PAYMENT API METHODS
  // ==========================================

  async getPaymentMethods(
    params: WhmcsGetPayMethodsParams
  ): Promise<WhmcsPaymentMethodListResponse> {
    return this.makeRequest<WhmcsPaymentMethodListResponse>("GetPayMethods", params);
  }

  async getPaymentGateways(): Promise<WhmcsPaymentGatewayListResponse> {
    return this.makeRequest<WhmcsPaymentGatewayListResponse>("GetPaymentMethods", {});
  }

  // ==========================================
  // SSO API METHODS
  // ==========================================

  async createSsoToken(params: WhmcsCreateSsoTokenParams): Promise<WhmcsSsoResponse> {
    return this.makeRequest<WhmcsSsoResponse>("CreateSsoToken", params);
  }

  // ==========================================
  // UTILITY METHODS
  // ==========================================

  getBaseUrl(): string {
    return this.configService.getBaseUrl();
  }

  /**
   * Determine request priority based on action type
   */
  private getRequestPriority(action: string): number {
    // High priority actions (critical for user experience)
    const highPriorityActions = [
      "ValidateLogin",
      "GetClientDetails",
      "GetInvoice",
      "CapturePayment",
      "CreateSsoToken",
    ];

    // Medium priority actions (important but can wait)
    const mediumPriorityActions = ["GetInvoices", "GetClientsProducts", "GetPayMethods"];

    if (highPriorityActions.includes(action)) {
      return 8; // High priority
    } else if (mediumPriorityActions.includes(action)) {
      return 5; // Medium priority
    } else {
      return 2; // Low priority (default)
    }
  }

  /**
   * Get connection statistics
   */
  getConnectionStats(): WhmcsConnectionStats {
    return this.httpClient.getStats();
  }

  /**
   * Reset connection statistics
   */
  resetConnectionStats(): void {
    this.httpClient.resetStats();
  }

  /**
   * Get configuration (sanitized for logging)
   */
  getConfig() {
    const config = this.configService.getConfig();
    return {
      baseUrl: config.baseUrl,
      timeout: config.timeout,
      retryAttempts: config.retryAttempts,
      retryDelay: config.retryDelay,
    };
  }

  /**
   * Get user-friendly error message
   */
  getUserFriendlyErrorMessage(error: unknown): string {
    return this.errorHandler.getUserFriendlyMessage(error);
  }

  /**
   * Check if error is already a handled exception
   */
  private isHandledException(error: unknown): boolean {
    return (
      error instanceof Error &&
      (error.name.includes("Exception") || error.message.includes("WHMCS"))
    );
  }
}
