import { Injectable, Inject } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import { WhmcsService } from "@bff/integrations/whmcs/whmcs.service";
import { MappingsService } from "@bff/modules/id-mappings/mappings.service";
import { getErrorMessage } from "@bff/core/utils/error.util";
import type { InvoiceHealthStatus, InvoiceServiceStats } from "../types/invoice-monitoring.types";

/**
 * Service responsible for health checks and monitoring of invoice services
 */
@Injectable()
export class InvoiceHealthService {
  private stats: InvoiceServiceStats = {
    totalInvoicesRetrieved: 0,
    totalPaymentLinksCreated: 0,
    totalSsoLinksCreated: 0,
    averageResponseTime: 0,
  };

  constructor(
    private readonly whmcsService: WhmcsService,
    private readonly mappingsService: MappingsService,
    @Inject(Logger) private readonly logger: Logger
  ) {}

  /**
   * Perform comprehensive health check
   */
  async healthCheck(): Promise<InvoiceHealthStatus> {
    try {
      const checks = await Promise.allSettled([
        this.checkWhmcsHealth(),
        this.checkMappingsHealth(),
      ]);

      const whmcsResult = checks[0];
      const mappingsResult = checks[1];

      const isHealthy =
        whmcsResult.status === "fulfilled" &&
        whmcsResult.value &&
        mappingsResult.status === "fulfilled" &&
        mappingsResult.value;

      return {
        status: isHealthy ? "healthy" : "unhealthy",
        details: {
          whmcsApi:
            whmcsResult.status === "fulfilled" && whmcsResult.value ? "connected" : "disconnected",
          mappingsService:
            mappingsResult.status === "fulfilled" && mappingsResult.value
              ? "available"
              : "unavailable",
          timestamp: new Date().toISOString(),
        },
      };
    } catch (error) {
      this.logger.error("Invoice service health check failed", {
        error: getErrorMessage(error),
      });

      return {
        status: "unhealthy",
        details: {
          error: getErrorMessage(error),
          timestamp: new Date().toISOString(),
        },
      };
    }
  }

  /**
   * Get service statistics
   */
  getStats(): InvoiceServiceStats {
    return { ...this.stats };
  }

  /**
   * Reset service statistics
   */
  resetStats(): void {
    this.stats = {
      totalInvoicesRetrieved: 0,
      totalPaymentLinksCreated: 0,
      totalSsoLinksCreated: 0,
      averageResponseTime: 0,
    };
  }

  /**
   * Record invoice retrieval
   */
  recordInvoiceRetrieval(responseTime: number): void {
    this.stats.totalInvoicesRetrieved++;
    this.updateAverageResponseTime(responseTime);
    this.stats.lastRequestTime = new Date();
  }

  /**
   * Record payment link creation
   */
  recordPaymentLinkCreation(responseTime: number): void {
    this.stats.totalPaymentLinksCreated++;
    this.updateAverageResponseTime(responseTime);
    this.stats.lastRequestTime = new Date();
  }

  /**
   * Record SSO link creation
   */
  recordSsoLinkCreation(responseTime: number): void {
    this.stats.totalSsoLinksCreated++;
    this.updateAverageResponseTime(responseTime);
    this.stats.lastRequestTime = new Date();
  }

  /**
   * Record error
   */
  recordError(): void {
    this.stats.lastErrorTime = new Date();
  }

  /**
   * Check WHMCS service health
   */
  private async checkWhmcsHealth(): Promise<boolean> {
    try {
      return await this.whmcsService.healthCheck();
    } catch (error) {
      this.logger.warn("WHMCS health check failed", {
        error: getErrorMessage(error),
      });
      return false;
    }
  }

  /**
   * Check mappings service health
   */
  private async checkMappingsHealth(): Promise<boolean> {
    try {
      // Simple check to see if mappings service is responsive
      // We don't want to create test data, so we'll just check if the service responds
      await this.mappingsService.findByUserId("health-check-test");
      return true;
    } catch (error) {
      // We expect this to fail for a non-existent user, but if the service responds, it's healthy
      const errorMessage = getErrorMessage(error);

      // If it's a "not found" error, the service is working
      if (errorMessage.toLowerCase().includes("not found")) {
        return true;
      }

      this.logger.warn("Mappings service health check failed", {
        error: errorMessage,
      });
      return false;
    }
  }

  /**
   * Update average response time
   */
  private updateAverageResponseTime(responseTime: number): void {
    const totalRequests =
      this.stats.totalInvoicesRetrieved +
      this.stats.totalPaymentLinksCreated +
      this.stats.totalSsoLinksCreated;

    if (totalRequests === 1) {
      this.stats.averageResponseTime = responseTime;
    } else {
      this.stats.averageResponseTime =
        (this.stats.averageResponseTime * (totalRequests - 1) + responseTime) / totalRequests;
    }
  }

  /**
   * Get health summary
   */
  async getHealthSummary(): Promise<{
    status: string;
    uptime: number;
    stats: InvoiceServiceStats;
    lastCheck: string;
  }> {
    const health = await this.healthCheck();

    return {
      status: health.status,
      uptime: process.uptime(),
      stats: this.getStats(),
      lastCheck: new Date().toISOString(),
    };
  }
}
