import { Injectable, NotFoundException, Inject } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import { getErrorMessage } from "@bff/core/utils/error.util";
import { WhmcsConnectionOrchestratorService } from "../connection/services/whmcs-connection-orchestrator.service";
import { WhmcsCacheService } from "../cache/whmcs-cache.service";
import type {
  WhmcsValidateLoginParams,
  WhmcsAddClientParams,
  WhmcsClientResponse,
  WhmcsAddClientResponse,
  WhmcsValidateLoginResponse,
} from "@customer-portal/domain/customer";
import { Providers as CustomerProviders, type WhmcsClient } from "@customer-portal/domain/customer";

@Injectable()
export class WhmcsClientService {
  constructor(
    private readonly connectionService: WhmcsConnectionOrchestratorService,
    private readonly cacheService: WhmcsCacheService,
    @Inject(Logger) private readonly logger: Logger
  ) {}

  /**
   * Validate client login credentials
   */
  async validateLogin(
    email: string,
    password: string
  ): Promise<{ userId: number; passwordHash: string }> {
    try {
      const params: WhmcsValidateLoginParams = {
        email,
        password2: password,
      };

      const response: WhmcsValidateLoginResponse =
        await this.connectionService.validateLogin(params);

      this.logger.log(`Validated login for email: ${email}`);
      return {
        userId: response.userid,
        passwordHash: response.passwordhash,
      };
    } catch (error) {
      this.logger.error(`Failed to validate login for email: ${email}`, {
        error: getErrorMessage(error),
      });
      throw error;
    }
  }

  /**
   * Get client details by ID
   * Returns WhmcsClient (type inferred from domain mapper)
   */
  async getClientDetails(clientId: number): Promise<WhmcsClient> {
    try {
      // Try cache first
      const cached = await this.cacheService.getClientData(clientId);
      if (cached) {
        this.logger.debug(`Cache hit for client: ${clientId}`);
        return cached;
      }

      const response = await this.connectionService.getClientDetails(clientId);

      if (!response || !response.client) {
        this.logger.error(`WHMCS API did not return client data for client ID: ${clientId}`, {
          hasResponse: !!response,
          responseKeys: response ? Object.keys(response) : [],
        });
        throw new NotFoundException(`Client ${clientId} not found`);
      }

      const client = CustomerProviders.Whmcs.transformWhmcsClientResponse(response);
      await this.cacheService.setClientData(client.id, client);

      this.logger.log(`Fetched client details for client ${clientId}`);
      return client;
    } catch (error) {
      this.logger.error(`Failed to fetch client details for client ${clientId}`, {
        error: getErrorMessage(error),
      });
      throw error;
    }
  }

  /**
   * Get client details by email
   * Returns WhmcsClient (type inferred from domain mapper)
   */
  async getClientDetailsByEmail(email: string): Promise<WhmcsClient> {
    try {
      const response = await this.connectionService.getClientDetailsByEmail(email);

      if (!response || !response.client) {
        this.logger.error(`WHMCS API did not return client data for email: ${email}`, {
          hasResponse: !!response,
          responseKeys: response ? Object.keys(response) : [],
        });
        throw new NotFoundException(`Client with email ${email} not found`);
      }

      const client = CustomerProviders.Whmcs.transformWhmcsClientResponse(response);
      await this.cacheService.setClientData(client.id, client);

      this.logger.log(`Fetched client details by email: ${email}`);
      return client;
    } catch (error) {
      this.logger.error(`Failed to fetch client details by email: ${email}`, {
        error: getErrorMessage(error),
      });
      throw error;
    }
  }

  /**
   * Update client details
   */
  async updateClient(
    clientId: number,
    updateData: Partial<WhmcsClientResponse["client"]>
  ): Promise<void> {
    try {
      await this.connectionService.updateClient(clientId, updateData);

      // Invalidate client cache after update
      await this.cacheService.invalidateClientCache(clientId);

      this.logger.log(`Successfully updated WHMCS client ${clientId}`);
    } catch (error: unknown) {
      this.logger.error(`Failed to update WHMCS client ${clientId}`, {
        error: getErrorMessage(error),
        updateData,
      });
      throw error;
    }
  }

  /**
   * Add new client
   */
  async addClient(clientData: WhmcsAddClientParams): Promise<{ clientId: number }> {
    try {
      const response: WhmcsAddClientResponse = await this.connectionService.addClient(clientData);

      this.logger.log(`Created new client: ${response.clientid}`);
      return { clientId: response.clientid };
    } catch (error) {
      this.logger.error(`Failed to create new client`, {
        error: getErrorMessage(error),
        email: clientData.email,
      });
      throw error;
    }
  }

  /**
   * Invalidate cache for a user
   */
  async invalidateUserCache(userId: string): Promise<void> {
    await this.cacheService.invalidateUserCache(userId);
    this.logger.log(`Invalidated cache for user ${userId}`);
  }
}
