import { Injectable, Inject, BadRequestException } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import { extractErrorMessage } from "@bff/core/utils/error.util.js";
import { FreebitClientService } from "./freebit-client.service.js";
import { FreebitMapperService } from "./freebit-mapper.service.js";
import { FreebitAuthService } from "./freebit-auth.service.js";
import type {
  FreebitAccountDetailsRequest,
  FreebitAccountDetailsResponse,
  SimDetails,
} from "../interfaces/freebit.types.js";

/**
 * Service for Freebit account/SIM details operations.
 * Handles fetching SIM details and health checks.
 */
@Injectable()
export class FreebitAccountService {
  constructor(
    private readonly client: FreebitClientService,
    private readonly mapper: FreebitMapperService,
    private readonly auth: FreebitAuthService,
    @Inject(Logger) private readonly logger: Logger
  ) {}

  /**
   * Get SIM account details with endpoint fallback
   */
  async getSimDetails(account: string): Promise<SimDetails> {
    try {
      const request: Omit<FreebitAccountDetailsRequest, "authKey"> = {
        version: "2",
        requestDatas: [{ kind: "MVNO", account }],
      };

      const config = this.auth.getConfig();
      const configured = config.detailsEndpoint || "/master/getAcnt/";
      const candidates = [
        ...new Set([
          configured,
          configured.replace(/\/$/, ""),
          "/master/getAcnt/",
          "/master/getAcnt",
          "/mvno/getAccountDetail/",
          "/mvno/getAccountDetail",
          "/mvno/getAcntDetail/",
          "/mvno/getAcntDetail",
          "/mvno/getAccountInfo/",
          "/mvno/getAccountInfo",
          "/mvno/getSubscriberInfo/",
          "/mvno/getSubscriberInfo",
          "/mvno/getInfo/",
          "/mvno/getInfo",
          "/master/getDetail/",
          "/master/getDetail",
        ]),
      ];

      let response: FreebitAccountDetailsResponse | undefined;
      let lastError: unknown;

      for (const ep of candidates) {
        try {
          if (ep !== candidates[0]) {
            this.logger.warn(`Retrying Freebit account details with alternative endpoint: ${ep}`);
          }
          // eslint-disable-next-line no-await-in-loop -- Endpoint fallback requires sequential attempts
          response = await this.client.makeAuthenticatedRequest<
            FreebitAccountDetailsResponse,
            typeof request
          >(ep, request);
          break;
        } catch (err: unknown) {
          lastError = err;
          if (extractErrorMessage(err).includes("HTTP 404")) {
            continue; // try next endpoint for 404 (endpoint not found)
          }
          // For non-404 errors (auth failures, rate limits, 500s, etc.), fail fast
          break;
        }
      }

      if (!response) {
        if (lastError instanceof Error) {
          throw lastError;
        }
        throw new Error("Failed to get SIM details from any endpoint");
      }

      return await this.mapper.mapToSimDetails(response);
    } catch (error) {
      const message = extractErrorMessage(error);
      this.logger.error(`Failed to get SIM details for account ${account}`, {
        account,
        error: message,
      });
      throw new BadRequestException(`Failed to get SIM details: ${message}`);
    }
  }

  /**
   * Health check - test API connectivity
   */
  async healthCheck(): Promise<boolean> {
    try {
      // Try a simple endpoint first
      const simpleCheck = await this.client.makeSimpleRequest("/");
      if (simpleCheck) {
        return true;
      }

      // If simple check fails, try authenticated request
      await this.auth.getAuthKey();
      return true;
    } catch (error) {
      this.logger.debug("Freebit health check failed", {
        error: extractErrorMessage(error),
      });
      return false;
    }
  }
}
