import { Injectable, Inject, OnModuleInit } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import { getErrorMessage } from "@bff/core/utils/error.util";
import { WhmcsConfigService } from "../config/whmcs-config.service";
import { WhmcsHttpClientService } from "./whmcs-http-client.service";
import { WhmcsErrorHandlerService } from "./whmcs-error-handler.service";
import { WhmcsApiMethodsService } from "./whmcs-api-methods.service";
import { WhmcsRequestQueueService } from "@bff/core/queue/services/whmcs-request-queue.service";
import type {
  WhmcsAddClientParams,
  WhmcsValidateLoginParams,
  WhmcsCreateSsoTokenParams,
} from "@customer-portal/domain/customer";
import type {
  WhmcsGetInvoicesParams,
  WhmcsCreateInvoiceParams,
  WhmcsUpdateInvoiceParams,
  WhmcsCapturePaymentParams,
} from "@customer-portal/domain/billing";
import type { WhmcsGetPayMethodsParams } from "@customer-portal/domain/payments";
import type { WhmcsGetClientsProductsParams } from "@customer-portal/domain/subscriptions";
import type { WhmcsErrorResponse } from "@customer-portal/domain/common";
import type { WhmcsRequestOptions, WhmcsConnectionStats } from "../types/connection.types";

/**
 * Main orchestrator service for WHMCS connections
 * Coordinates configuration, HTTP client, error handling, and API methods
 */
@Injectable()
export class WhmcsConnectionOrchestratorService implements OnModuleInit {
  constructor(
    @Inject(Logger) private readonly logger: Logger,
    private readonly configService: WhmcsConfigService,
    private readonly httpClient: WhmcsHttpClientService,
    private readonly errorHandler: WhmcsErrorHandlerService,
    private readonly apiMethods: WhmcsApiMethodsService,
    private readonly requestQueue: WhmcsRequestQueueService
  ) {}

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

      // Test connection
      const isAvailable = await this.apiMethods.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: getErrorMessage(error),
      });
    }
  }

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

  /**
   * Make a request to WHMCS API with full error handling and queue management
   */
  async makeRequest<T>(
    action: string,
    params: Record<string, unknown> = {},
    options: WhmcsRequestOptions = {}
  ): Promise<T> {
    // Wrap the actual request in the queue to prevent race conditions
    return this.requestQueue.execute(
      async () => {
        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, params);
          }

          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, action, params);
        }
      },
      {
        priority: this.getRequestPriority(action),
        timeout: options.timeout,
        retryAttempts: options.retryAttempts,
        retryDelay: options.retryDelay,
      }
    );
  }

  /**
   * Make a high-priority request to WHMCS API (jumps queue)
   */
  async makeHighPriorityRequest<T>(
    action: string,
    params: Record<string, unknown> = {},
    options: WhmcsRequestOptions = {}
  ): Promise<T> {
    return this.requestQueue.executeHighPriority(async () => {
      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, params);
        }

        return response.data as T;
      } catch (error) {
        if (this.isHandledException(error)) {
          throw error;
        }
        this.errorHandler.handleRequestError(error, action, params);
      }
    });
  }

  /**
   * 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> {
    return this.apiMethods.healthCheck();
  }

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

  async getSystemInfo(): Promise<unknown> {
    return this.apiMethods.getSystemInfo();
  }

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

  async getClientDetails(clientId: number) {
    return this.apiMethods.getClientDetails(clientId);
  }

  async getClientDetailsByEmail(email: string) {
    return this.apiMethods.getClientDetailsByEmail(email);
  }

  async updateClient(clientId: number, updateData: Record<string, unknown>) {
    return this.apiMethods.updateClient(clientId, updateData);
  }

  async addClient(params: WhmcsAddClientParams) {
    return this.apiMethods.addClient(params);
  }

  async validateLogin(params: WhmcsValidateLoginParams) {
    return this.apiMethods.validateLogin(params);
  }

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

  async getInvoices(params: WhmcsGetInvoicesParams = {}) {
    return this.apiMethods.getInvoices(params);
  }

  async getInvoice(invoiceId: number) {
    return this.apiMethods.getInvoice(invoiceId);
  }

  async createInvoice(params: WhmcsCreateInvoiceParams) {
    return this.apiMethods.createInvoice(params);
  }

  async updateInvoice(params: WhmcsUpdateInvoiceParams) {
    return this.apiMethods.updateInvoice(params);
  }

  async capturePayment(params: WhmcsCapturePaymentParams) {
    return this.apiMethods.capturePayment(params);
  }

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

  async addOrder(params: Record<string, unknown>) {
    return this.apiMethods.addOrder(params);
  }

  async getOrders(params: Record<string, unknown> = {}) {
    return this.apiMethods.getOrders(params);
  }

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

  /**
   * Accept an order (requires admin authentication)
   */
  async acceptOrder(orderId: number) {
    return this.apiMethods.acceptOrder(orderId);
  }

  async cancelOrder(orderId: number) {
    return this.apiMethods.cancelOrder(orderId);
  }

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

  async getClientsProducts(params: WhmcsGetClientsProductsParams) {
    return this.apiMethods.getClientsProducts(params);
  }

  async getCatalogProducts() {
    return this.apiMethods.getCatalogProducts();
  }

  async getProducts() {
    return this.apiMethods.getProducts();
  }

  async getCurrencies() {
    return this.apiMethods.getCurrencies();
  }

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

  async getPaymentMethods(params: WhmcsGetPayMethodsParams) {
    return this.apiMethods.getPaymentMethods(params);
  }

  async getPaymentGateways() {
    return this.apiMethods.getPaymentGateways();
  }

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

  async createSsoToken(params: WhmcsCreateSsoTokenParams) {
    return this.apiMethods.createSsoToken(params);
  }

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

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

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

  /**
   * 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"))
    );
  }
}
