import { Injectable, Inject, BadRequestException } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import { SubscriptionsService } from "../../subscriptions.service";
import { getErrorMessage } from "@bff/core/utils/error.util";
import type { SimValidationResult } from "../interfaces/sim-base.interface";
import { MappingsService } from "@bff/modules/id-mappings/mappings.service";
import { WhmcsService } from "@bff/integrations/whmcs/whmcs.service";

@Injectable()
export class SimValidationService {
  constructor(
    private readonly subscriptionsService: SubscriptionsService,
    private readonly mappingsService: MappingsService,
    private readonly whmcsService: WhmcsService,
    @Inject(Logger) private readonly logger: Logger
  ) {}

  /**
   * Check if a subscription is a SIM service and extract account identifier
   */
  async validateSimSubscription(
    userId: string,
    subscriptionId: number
  ): Promise<SimValidationResult> {
    try {
      // Get subscription details to verify it's a SIM service
      const subscription = await this.subscriptionsService.getSubscriptionById(
        userId,
        subscriptionId
      );

      // Check if this is a SIM service
      const isSimService =
        subscription.productName.toLowerCase().includes("sim") ||
        subscription.groupName?.toLowerCase().includes("sim");

      if (!isSimService) {
        throw new BadRequestException("This subscription is not a SIM service");
      }

      // For SIM services, the account identifier (phone number) can be stored in multiple places
      let account = "";
      let accountSource = "";

      // 1. Try domain field first
      if (subscription.domain && subscription.domain.trim()) {
        account = subscription.domain.trim();
        accountSource = "subscription.domain";
        this.logger.log(`Found SIM account in domain field: ${account}`, {
          userId,
          subscriptionId,
          source: accountSource,
        });
      }

      // 2. If no domain, check custom fields for phone number/MSISDN
      if (!account && subscription.customFields) {
        account = this.extractAccountFromCustomFields(subscription.customFields, subscriptionId);
        if (account) {
          accountSource = "subscription.customFields";
          this.logger.log(`Found SIM account in custom fields: ${account}`, {
            userId,
            subscriptionId,
            source: accountSource,
          });
        }
      }

      // 3. If still no account, check if subscription ID looks like a phone number
      if (!account && subscription.orderNumber) {
        const orderNum = subscription.orderNumber.toString();
        if (/^\d{10,11}$/.test(orderNum)) {
          account = orderNum;
          accountSource = "subscription.orderNumber";
          this.logger.log(`Found SIM account in order number: ${account}`, {
            userId,
            subscriptionId,
            source: accountSource,
          });
        }
      }

      // 4. Final fallback - get phone number from WHMCS account
      if (!account) {
        try {
          const mapping = await this.mappingsService.findByUserId(userId);
          if (mapping?.whmcsClientId) {
            const client = await this.whmcsService.getClientDetails(mapping.whmcsClientId);
            if (client?.phonenumber) {
              account = client.phonenumber;
              accountSource = "whmcs.account.phonenumber";
              this.logger.log(
                `Found SIM account in WHMCS account phone number: ${account}`,
                {
                  userId,
                  subscriptionId,
                  productName: subscription.productName,
                  whmcsClientId: mapping.whmcsClientId,
                  source: accountSource,
                }
              );
            }
          }
        } catch (error) {
          this.logger.warn(
            `Failed to retrieve phone number from WHMCS account for user ${userId}`,
            {
              error: getErrorMessage(error),
              userId,
              subscriptionId,
            }
          );
        }

        // If still no account found, throw an error
        if (!account) {
          throw new BadRequestException(
            `No SIM account identifier (phone number) found for subscription ${subscriptionId}. ` +
            `Please ensure the subscription has a phone number in the domain field, custom fields, or in your WHMCS account profile.`
          );
        }
      }

      // Clean up the account format (remove hyphens, spaces, etc.)
      account = account.replace(/[-\s()]/g, "");

      // Skip phone number format validation for testing
      // In production, you might want to add validation back:
      // const cleanAccount = account.replace(/^\+81/, '0'); // Convert +81 to 0
      // if (!/^0\d{9,10}$/.test(cleanAccount)) {
      //   throw new BadRequestException(`Invalid SIM account format: ${account}. Expected Japanese phone number format (10-11 digits starting with 0).`);
      // }
      // account = cleanAccount;

      this.logger.log(`Using SIM account: ${account} (from ${accountSource})`, {
        userId,
        subscriptionId,
        account,
        source: accountSource,
        note: "Phone number format validation skipped for testing",
      });

      return { account };
    } catch (error) {
      const sanitizedError = getErrorMessage(error);
      this.logger.error(
        `Failed to validate SIM subscription ${subscriptionId} for user ${userId}`,
        {
          error: sanitizedError,
        }
      );
      throw error;
    }
  }

  /**
   * Extract account identifier from custom fields
   */
  private extractAccountFromCustomFields(
    customFields: Record<string, unknown>,
    subscriptionId: number
  ): string {
    // Common field names for SIM phone numbers in WHMCS
    const phoneFields = [
      "phone",
      "msisdn",
      "phonenumber",
      "phone_number",
      "mobile",
      "sim_phone",
      "Phone Number",
      "MSISDN",
      "Phone",
      "Mobile",
      "SIM Phone",
      "PhoneNumber",
      "phone_number",
      "mobile_number",
      "sim_number",
      "account_number",
      "Account Number",
      "SIM Account",
      "Phone Number (SIM)",
      "Mobile Number",
      // Specific field names that might contain the SIM number
      "SIM Number",
      "SIM_Number",
      "sim_number",
      "SIM_Phone_Number",
      "Phone_Number_SIM",
      "Mobile_SIM_Number",
      "SIM_Account_Number",
      "ICCID",
      "iccid",
      "IMSI",
      "imsi",
      "EID",
      "eid",
      // Additional variations
      "SIM_Data",
      "SIM_Info",
      "SIM_Details",
    ];

    for (const fieldName of phoneFields) {
      const rawValue = customFields[fieldName];
      if (rawValue !== undefined && rawValue !== null && rawValue !== "") {
        const accountValue = this.formatCustomFieldValue(rawValue);
        this.logger.log(`Found SIM account in custom field '${fieldName}': ${accountValue}`, {
          subscriptionId,
          fieldName,
          account: accountValue,
        });
        return accountValue;
      }
    }

    // If still no account found, log all available custom fields for debugging
    this.logger.warn(`No SIM account found in custom fields for subscription ${subscriptionId}`, {
      subscriptionId,
      availableFields: Object.keys(customFields),
      customFields,
      searchedFields: phoneFields,
    });

    return "";
  }

  /**
   * Debug method to check subscription data for SIM services
   */
  async debugSimSubscription(
    userId: string,
    subscriptionId: number
  ): Promise<Record<string, unknown>> {
    try {
      const subscription = await this.subscriptionsService.getSubscriptionById(
        userId,
        subscriptionId
      );

      // Get WHMCS account phone number for debugging
      let whmcsAccountPhone: string | undefined;
      try {
        const mapping = await this.mappingsService.findByUserId(userId);
        if (mapping?.whmcsClientId) {
          const client = await this.whmcsService.getClientDetails(mapping.whmcsClientId);
          whmcsAccountPhone = client?.phonenumber;
        }
      } catch (error) {
        this.logger.warn(`Failed to fetch WHMCS account phone for debugging`, {
          error: getErrorMessage(error),
        });
      }

      return {
        subscriptionId,
        productName: subscription.productName,
        domain: subscription.domain,
        orderNumber: subscription.orderNumber,
        customFields: subscription.customFields,
        isSimService:
          subscription.productName.toLowerCase().includes("sim") ||
          subscription.groupName?.toLowerCase().includes("sim"),
        groupName: subscription.groupName,
        status: subscription.status,
        whmcsAccountPhone,
        allCustomFieldKeys: Object.keys(subscription.customFields || {}),
        allCustomFieldValues: subscription.customFields,
      };
    } catch (error) {
      const sanitizedError = getErrorMessage(error);
      this.logger.error(`Failed to debug subscription ${subscriptionId}`, {
        error: sanitizedError,
      });
      throw error;
    }
  }

  private formatCustomFieldValue(value: unknown): string {
    if (typeof value === "string") {
      return value;
    }

    if (typeof value === "number" || typeof value === "boolean") {
      return String(value);
    }

    if (value instanceof Date) {
      return value.toISOString();
    }

    if (typeof value === "object" && value !== null) {
      try {
        return JSON.stringify(value);
      } catch {
        return "[unserializable]";
      }
    }

    return "";
  }
}
