import { Injectable, OnModuleInit, Inject } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import { ConfigService } from "@nestjs/config";
import { getErrorMessage } from "@bff/core/utils/error.util";
import { SalesforceConnection } from "./services/salesforce-connection.service";
import {
  SalesforceAccountService,
  type SalesforceAccountPortalUpdate,
} from "./services/salesforce-account.service";
import { SalesforceOperationException } from "@bff/core/exceptions/domain-exceptions";
import type { SalesforceOrderRecord } from "@customer-portal/domain/orders";

/**
 * Salesforce Service - Facade for Salesforce operations
 *
 * Account Methods (Actually Used):
 * - findAccountByCustomerNumber() - Used in signup/WHMCS linking workflows
 * - getAccountDetails() - Used in signup to check WH_Account__c field
 *
 * Order Methods:
 * - updateOrder() - Used in order provisioning
 * - getOrder() - Used to fetch order details
 *
 * Note: Internet Eligibility checking happens in internet-catalog.service.ts
 */
@Injectable()
export class SalesforceService implements OnModuleInit {
  constructor(
    private configService: ConfigService,
    private connection: SalesforceConnection,
    private accountService: SalesforceAccountService,
    @Inject(Logger) private readonly logger: Logger
  ) {}

  async onModuleInit() {
    try {
      await this.connection.connect();
      if (!this.connection.isConnected()) {
        this.logger.warn(
          "Salesforce connection is not established. Running without Salesforce integration."
        );
        return;
      }
    } catch (error) {
      const nodeEnv =
        this.configService.get<string>("NODE_ENV") || process.env.NODE_ENV || "development";
      const isProd = nodeEnv === "production";
      if (isProd) {
        this.logger.error("Failed to initialize Salesforce connection");
      } else {
        this.logger.error(`Failed to initialize Salesforce connection: ${getErrorMessage(error)}`);
      }
    }
  }

  // === ACCOUNT METHODS (Actually Used) ===

  async findAccountByCustomerNumber(customerNumber: string): Promise<{ id: string } | null> {
    return this.accountService.findByCustomerNumber(customerNumber);
  }

  async findAccountWithDetailsByCustomerNumber(
    customerNumber: string
  ): Promise<{ id: string; WH_Account__c?: string | null; Name?: string | null } | null> {
    return this.accountService.findWithDetailsByCustomerNumber(customerNumber);
  }

  async getAccountDetails(
    accountId: string
  ): Promise<{ id: string; WH_Account__c?: string | null; Name?: string | null } | null> {
    return this.accountService.getAccountDetails(accountId);
  }

  async updateAccountPortalFields(
    accountId: string,
    update: SalesforceAccountPortalUpdate
  ): Promise<void> {
    await this.accountService.updatePortalFields(accountId, update);
  }

  // === ORDER METHODS (For Order Provisioning) ===

  async updateOrder(orderData: Partial<SalesforceOrderRecord> & { Id: string }): Promise<void> {
    const orderId = orderData.Id;
    try {
      if (!this.connection.isConnected()) {
        throw new SalesforceOperationException("Salesforce connection not available", {
          operation: "updateOrder",
          orderId,
        });
      }

      const sobject = this.connection.sobject("Order");
      if (!sobject) {
        throw new SalesforceOperationException("Failed to get Salesforce Order sobject", {
          operation: "updateOrder",
          orderId,
        });
      }

      if (sobject.update) {
        await sobject.update(orderData);
      } else {
        throw new SalesforceOperationException(
          "Salesforce Order sobject does not support update operation",
          {
            operation: "updateOrder",
            orderId,
          }
        );
      }

      this.logger.log("Order updated in Salesforce", {
        orderId: orderData.Id,
        fields: Object.keys(orderData).filter(k => k !== "Id"),
      });
    } catch (error) {
      this.logger.error("Failed to update order in Salesforce", {
        orderId: orderData.Id,
        error: getErrorMessage(error),
      });
      throw error;
    }
  }

  async getOrder(orderId: string): Promise<SalesforceOrderRecord | null> {
    try {
      if (!this.connection.isConnected()) {
        throw new SalesforceOperationException("Salesforce connection not available", {
          operation: "getOrder",
          orderId,
        });
      }

      const result = (await this.connection.query(
        `SELECT Id, Status, Type, Activation_Status__c, WHMCS_Order_ID__c, 
                Activation_Error_Code__c, Activation_Error_Message__c,
                AccountId, Account.Name
         FROM Order 
         WHERE Id = '${orderId}' 
         LIMIT 1`,
        { label: "orders:integration:getOrder" }
      )) as { records: SalesforceOrderRecord[]; totalSize: number };

      return result.records?.[0] || null;
    } catch (error) {
      this.logger.error("Failed to get order from Salesforce", {
        orderId,
        error: getErrorMessage(error),
      });
      throw error;
    }
  }

  // === HEALTH CHECK ===

  healthCheck(): boolean {
    try {
      return this.connection.isConnected();
    } catch (error) {
      this.logger.error("Salesforce health check failed", {
        error: getErrorMessage(error),
      });
      return false;
    }
  }
}
