import { Injectable, Inject } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { BaseCatalogService } from "./base-catalog.service";
import { CatalogCacheService } from "./catalog-cache.service";
import type {
  SalesforceProduct2WithPricebookEntries,
  SimCatalogProduct,
  SimActivationFeeCatalogItem,
} from "@customer-portal/domain/catalog";
import { Providers as CatalogProviders } from "@customer-portal/domain/catalog";
import { MappingsService } from "@bff/modules/id-mappings/mappings.service";
import { SalesforceConnection } from "@bff/integrations/salesforce/services/salesforce-connection.service";
import { Logger } from "nestjs-pino";
import { WhmcsConnectionOrchestratorService } from "@bff/integrations/whmcs/connection/services/whmcs-connection-orchestrator.service";

@Injectable()
export class SimCatalogService extends BaseCatalogService {
  constructor(
    sf: SalesforceConnection,
    configService: ConfigService,
    @Inject(Logger) logger: Logger,
    private mappingsService: MappingsService,
    private whmcs: WhmcsConnectionOrchestratorService,
    private catalogCache: CatalogCacheService
  ) {
    super(sf, configService, logger);
  }

  async getPlans(): Promise<SimCatalogProduct[]> {
    const cacheKey = this.catalogCache.buildCatalogKey("sim", "plans");

    return this.catalogCache.getCachedCatalog(
      cacheKey,
      async () => {
        const soql = this.buildCatalogServiceQuery("SIM", [
          "SIM_Data_Size__c",
          "SIM_Plan_Type__c",
          "SIM_Has_Family_Discount__c",
          "Catalog_Order__c",
        ]);
        const records = await this.executeQuery<SalesforceProduct2WithPricebookEntries>(
          soql,
          "SIM Plans"
        );

        return records.map(record => {
          const entry = this.extractPricebookEntry(record);
          const product = CatalogProviders.Salesforce.mapSimProduct(record, entry);

          return {
            ...product,
            description: product.description ?? product.name,
          } satisfies SimCatalogProduct;
        });
      },
      {
        resolveDependencies: plans => ({
          productIds: plans.map(plan => plan.id).filter((id): id is string => Boolean(id)),
        }),
      }
    );
  }

  async getActivationFees(): Promise<SimActivationFeeCatalogItem[]> {
    const cacheKey = this.catalogCache.buildCatalogKey("sim", "activation-fees");

    return this.catalogCache.getCachedCatalog(
      cacheKey,
      async () => {
        const soql = this.buildProductQuery("SIM", "Activation", [
          "Catalog_Order__c",
          "Auto_Add__c",
          "Is_Default__c",
        ]);
        const records = await this.executeQuery<SalesforceProduct2WithPricebookEntries>(
          soql,
          "SIM Activation Fees"
        );

        const activationFees = records
          .map(record => {
            const entry = this.extractPricebookEntry(record);
            return CatalogProviders.Salesforce.mapSimActivationFee(record, entry);
          })
          .sort((a, b) => (a.displayOrder ?? 0) - (b.displayOrder ?? 0));

        if (activationFees.length === 0) {
          this.logger.warn("No SIM activation fees found in catalog");
          return activationFees;
        }

        const hasDefault = activationFees.some(
          fee => fee.catalogMetadata?.isDefault === true
        );

        if (!hasDefault) {
          this.logger.warn(
            "No default SIM activation fee configured. Marking the first fee as default."
          );
          activationFees[0] = {
            ...activationFees[0],
            catalogMetadata: {
              ...activationFees[0].catalogMetadata,
              isDefault: true,
            },
          };
        }

        return activationFees;
      },
      {
        resolveDependencies: products => ({
          productIds: products.map(product => product.id).filter((id): id is string => Boolean(id)),
        }),
      }
    );
  }

  async getAddons(): Promise<SimCatalogProduct[]> {
    const cacheKey = this.catalogCache.buildCatalogKey("sim", "addons");

    return this.catalogCache.getCachedCatalog(
      cacheKey,
      async () => {
        const soql = this.buildProductQuery("SIM", "Add-on", [
          "Billing_Cycle__c",
          "Catalog_Order__c",
          "Bundled_Addon__c",
          "Is_Bundled_Addon__c",
        ]);
        const records = await this.executeQuery<SalesforceProduct2WithPricebookEntries>(
          soql,
          "SIM Add-ons"
        );

        return records
          .map(record => {
            const entry = this.extractPricebookEntry(record);
            const product = CatalogProviders.Salesforce.mapSimProduct(record, entry);

            return {
              ...product,
              description: product.description ?? product.name,
            } satisfies SimCatalogProduct;
          })
          .sort((a, b) => (a.displayOrder ?? 0) - (b.displayOrder ?? 0));
      },
      {
        resolveDependencies: products => ({
          productIds: products.map(product => product.id).filter((id): id is string => Boolean(id)),
        }),
      }
    );
  }

  async getPlansForUser(userId: string): Promise<SimCatalogProduct[]> {
    try {
      // Get all plans first
      const allPlans = await this.getPlans();

      // Check if user has existing SIM services
      const hasExistingSim = await this.checkUserHasExistingSim(userId);

      if (hasExistingSim) {
        this.logger.log(`User ${userId} has existing SIM, showing family discount plans`);
        // Show family discount plans + regular plans for comparison
        return allPlans; // Family plans are included with simHasFamilyDiscount: true
      } else {
        this.logger.log(`User ${userId} has no existing SIM, showing regular plans only`);
        // Show only regular plans (hide family discount plans)
        return allPlans.filter(plan => !plan.simHasFamilyDiscount);
      }
    } catch (error) {
      this.logger.error(`Failed to get personalized SIM plans for user ${userId}`, error);
      // Fallback to all regular plans
      const allPlans = await this.getPlans();
      return allPlans.filter(plan => !plan.simHasFamilyDiscount);
    }
  }

  private async checkUserHasExistingSim(userId: string): Promise<boolean> {
    try {
      // Get user's WHMCS client ID
      const mapping = await this.mappingsService.findByUserId(userId);
      if (!mapping?.whmcsClientId) {
        return false;
      }

      // Check WHMCS for existing SIM services
      const products = await this.whmcs.getClientsProducts({ clientid: mapping.whmcsClientId });
      const services = (products?.products?.product || []) as Array<{
        groupname?: string;
        status?: string;
      }>;

      // Look for active SIM services
      const hasActiveSim = services.some(
        service =>
          String(service.groupname || "")
            .toLowerCase()
            .includes("sim") && String(service.status || "").toLowerCase() === "active"
      );

      return hasActiveSim;
    } catch (error) {
      this.logger.warn(`Failed to check existing SIM for user ${userId}`, error);
      return false; // Default to no existing SIM
    }
  }

  async getCatalogData() {
    const [plans, activationFees, addons] = await Promise.all([
      this.getPlans(),
      this.getActivationFees(),
      this.getAddons(),
    ]);
    return { plans, activationFees, addons };
  }
}
