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 { FreebitAuthService } from "./freebit-auth.service.js";
import type {
  FreebitEsimReissueRequest,
  FreebitEsimReissueResponse,
  FreebitEsimAddAccountRequest,
  FreebitEsimAddAccountResponse,
  FreebitEsimAccountActivationRequest,
  FreebitEsimAccountActivationResponse,
} from "../interfaces/freebit.types.js";

export interface EsimActivationParams {
  account: string;
  eid: string;
  planCode?: string;
  contractLine?: "4G" | "5G";
  aladinOperated?: "10" | "20";
  shipDate?: string;
  addKind?: "N" | "M" | "R"; // N:新規, M:MNP転入, R:再発行
  simKind?: "E0" | "E2" | "E3"; // E0:音声あり, E2:SMSなし, E3:SMSあり
  repAccount?: string;
  deliveryCode?: string;
  globalIp?: "10" | "20";
  mnp?: { reserveNumber: string; reserveExpireDate?: string };
  identity?: {
    firstnameKanji?: string;
    lastnameKanji?: string;
    firstnameZenKana?: string;
    lastnameZenKana?: string;
    gender?: string;
    birthday?: string;
  };
}

/**
 * Service for Freebit eSIM operations.
 * Handles eSIM profile reissue and activation.
 */
@Injectable()
export class FreebitEsimService {
  constructor(
    private readonly client: FreebitClientService,
    private readonly auth: FreebitAuthService,
    @Inject(Logger) private readonly logger: Logger
  ) {}

  /**
   * Reissue eSIM profile (simple version)
   */
  async reissueEsimProfile(account: string): Promise<void> {
    try {
      const request: Omit<FreebitEsimReissueRequest, "authKey"> = {
        requestDatas: [{ kind: "MVNO", account }],
      };

      await this.client.makeAuthenticatedRequest<FreebitEsimReissueResponse, typeof request>(
        "/mvno/reissueEsim/",
        request
      );

      this.logger.log(`Successfully reissued eSIM profile for account ${account}`);
    } catch (error) {
      const message = extractErrorMessage(error);
      this.logger.error(`Failed to reissue eSIM profile for account ${account}`, {
        account,
        error: message,
      });
      throw new BadRequestException(`Failed to reissue eSIM profile: ${message}`);
    }
  }

  /**
   * Reissue eSIM profile with enhanced options
   */
  async reissueEsimProfileEnhanced(
    account: string,
    newEid: string,
    options: { oldProductNumber?: string; oldEid?: string; planCode?: string } = {}
  ): Promise<void> {
    try {
      const request: Omit<FreebitEsimAddAccountRequest, "authKey"> = {
        aladinOperated: "20",
        account,
        eid: newEid,
        addKind: "R",
        ...(options.planCode !== undefined && { planCode: options.planCode }),
      };

      await this.client.makeAuthenticatedRequest<FreebitEsimAddAccountResponse, typeof request>(
        "/mvno/esim/addAcnt/",
        request
      );

      this.logger.log(`Successfully reissued eSIM profile via addAcnt for account ${account}`, {
        account,
        newEid,
        oldProductNumber: options.oldProductNumber,
        oldEid: options.oldEid,
      });
    } catch (error) {
      const message = extractErrorMessage(error);
      this.logger.error(`Failed to reissue eSIM profile via addAcnt for account ${account}`, {
        account,
        newEid,
        error: message,
      });
      throw new BadRequestException(`Failed to reissue eSIM profile: ${message}`);
    }
  }

  /**
   * Activate new eSIM account using PA05-41 (addAcct)
   */
  async activateEsimAccountNew(params: EsimActivationParams): Promise<void> {
    const {
      account,
      eid,
      planCode,
      contractLine,
      aladinOperated = "10",
      shipDate,
      addKind,
      simKind,
      repAccount,
      deliveryCode,
      globalIp,
      mnp,
      identity,
    } = params;

    if (!account || !eid) {
      throw new BadRequestException("activateEsimAccountNew requires account and eid");
    }

    const finalAddKind = addKind || "N";

    // Validate simKind: Required except when addKind is 'R' (reissue)
    if (finalAddKind !== "R" && !simKind) {
      throw new BadRequestException(
        "simKind is required for eSIM activation (use 'E0' for voice, 'E3' for SMS, 'E2' for data-only)"
      );
    }

    try {
      const payload: FreebitEsimAccountActivationRequest = {
        authKey: await this.auth.getAuthKey(),
        aladinOperated,
        createType: "new",
        eid,
        account,
        simkind: simKind || "E0",
        addKind: finalAddKind,
        planCode,
        contractLine,
        shipDate,
        repAccount,
        deliveryCode,
        globalIp,
        ...(mnp ? { mnp } : {}),
        ...(identity ? identity : {}),
      } as FreebitEsimAccountActivationRequest;

      await this.client.makeAuthenticatedJsonRequest<
        FreebitEsimAccountActivationResponse,
        FreebitEsimAccountActivationRequest
      >("/mvno/esim/addAcct/", payload);

      this.logger.log("Successfully activated new eSIM account via PA05-41", {
        account,
        planCode,
        contractLine,
        addKind: addKind || "N",
        scheduled: !!shipDate,
        mnp: !!mnp,
      });
    } catch (error) {
      const message = extractErrorMessage(error);
      this.logger.error(`Failed to activate new eSIM account ${account}`, {
        account,
        eid,
        planCode,
        addKind,
        error: message,
      });
      throw new BadRequestException(`Failed to activate new eSIM account: ${message}`);
    }
  }
}
