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 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;
    lastnameKanji?: string;
    firstnameKanji?: string;
    lastnameZenKana?: string;
    firstnameZenKana?: string;
    gender?: string; // Freebit uses 'M'/'W'/'C' (caller should map 'F' → 'W')
    birthday?: string;
  };
}

/**
 * Service for Freebit eSIM operations.
 * Handles eSIM profile reissue and activation.
 */
@Injectable()
export class FreebitEsimService {
  constructor(
    private readonly client: FreebitClientService,
    @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 }),
        ...(options.oldProductNumber && { oldProductNumber: options.oldProductNumber }),
        ...(options.oldEid && { oldEid: options.oldEid }),
      };

      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,
    } = 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)"
      );
    }

    this.logger.log("PA05-41 preparing eSIM activation payload", {
      account,
      addKind: finalAddKind,
      simKind: simKind || "E0",
      aladinOperated,
      hasMnp: !!mnp,
      hasReserveNumber: !!mnp?.reserveNumber,
      hasIdentity: !!(mnp?.lastnameKanji || mnp?.firstnameKanji),
      gender: mnp?.gender,
      planCode,
      contractLine,
    });

    try {
      // Note: authKey is injected by makeAuthenticatedJsonRequest
      // createType is not required when addKind is 'R' (reissue)
      const payload: Omit<FreebitEsimAccountActivationRequest, "authKey"> = {
        aladinOperated,
        ...(finalAddKind !== "R" && { createType: "new" }),
        eid,
        account,
        simkind: simKind || "E0",
        addKind: finalAddKind,
        planCode,
        contractLine,
        shipDate,
        repAccount,
        deliveryCode,
        globalIp,
        // MNP object includes both reservation info AND identity fields (all Level 2 per PA05-41 spec)
        ...(mnp ? { mnp } : {}),
      } as Omit<FreebitEsimAccountActivationRequest, "authKey">;

      // Log full payload details (excluding authKey) for MNP debugging
      this.logger.log("PA05-41 final payload to Freebit API", {
        account,
        eid,
        addKind: finalAddKind,
        simkind: simKind || "E0",
        aladinOperated,
        createType: finalAddKind === "R" ? "omitted" : "new",
        planCode,
        contractLine,
        shipDate: shipDate ?? "not-set",
        hasMnpObject: !!mnp,
        mnpFields: mnp
          ? {
              reserveNumber: mnp.reserveNumber ?? "MISSING",
              reserveExpireDate: mnp.reserveExpireDate ?? "not-set",
              lastnameKanji: mnp.lastnameKanji ? "present" : "missing",
              firstnameKanji: mnp.firstnameKanji ? "present" : "missing",
              lastnameZenKana: mnp.lastnameZenKana ? "present" : "missing",
              firstnameZenKana: mnp.firstnameZenKana ? "present" : "missing",
              gender: mnp.gender ?? "not-set",
              birthday: mnp.birthday ? "present" : "missing",
              totalFields: Object.keys(mnp).length,
            }
          : "no-mnp",
      });

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

      this.logger.log("Successfully activated new eSIM account via PA05-41", {
        account,
        planCode,
        contractLine,
        addKind: finalAddKind,
        scheduled: !!shipDate,
        isMnp: finalAddKind === "M",
      });
    } catch (error) {
      const message = extractErrorMessage(error);
      this.logger.error(`Failed to activate new eSIM account ${account}`, {
        account,
        eid,
        planCode,
        addKind: finalAddKind,
        aladinOperated,
        isMnp: finalAddKind === "M",
        hasMnpReserveNumber: !!mnp?.reserveNumber,
        mnpFieldCount: mnp ? Object.keys(mnp).length : 0,
        error: message,
      });
      throw new BadRequestException(`Failed to activate new eSIM account: ${message}`);
    }
  }
}
