/**
 * Salesforce Case Platform Events Subscriber
 *
 * Handles real-time Case Platform Events for:
 * - Case status updates
 *
 * Uses POKE approach: invalidate cache + SSE → portal refetches
 *
 * @see docs/integrations/salesforce/platform-events.md
 */

import { Injectable, Inject } from "@nestjs/common";
import type { OnModuleInit } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { Logger } from "nestjs-pino";
import {
  PubSubClientService,
  isDataCallback,
  extractPayload,
  extractStringField,
} from "./shared/index.js";
import { SupportCacheService } from "@bff/modules/support/support-cache.service.js";
import { RealtimeService } from "@bff/infra/realtime/realtime.service.js";

@Injectable()
export class CaseEventsSubscriber implements OnModuleInit {
  constructor(
    private readonly config: ConfigService,
    private readonly pubSubClient: PubSubClientService,
    private readonly supportCache: SupportCacheService,
    private readonly realtime: RealtimeService,
    @Inject(Logger) private readonly logger: Logger
  ) {}

  async onModuleInit(): Promise<void> {
    const channel = this.config.get<string>("SF_CASE_EVENT_CHANNEL")?.trim();

    if (!channel) {
      this.logger.debug("SF_CASE_EVENT_CHANNEL not configured; skipping case events");
      return;
    }

    try {
      await this.pubSubClient.subscribe(
        channel,
        this.handleCaseEvent.bind(this, channel),
        "case-platform-event"
      );
    } catch (error) {
      this.logger.warn("Failed to subscribe to Case Platform Events", {
        channel,
        error: error instanceof Error ? error.message : String(error),
      });
    }
  }

  /**
   * Handle Case Platform Events (Case_Status_Update__e)
   *
   * Required fields:
   * - Case_Id__c
   * - Account_Id__c
   */
  private async handleCaseEvent(
    channel: string,
    _subscription: { topicName?: string },
    callbackType: string,
    data: unknown
  ): Promise<void> {
    if (!isDataCallback(callbackType)) return;

    const payload = extractPayload(data);
    const caseId = extractStringField(payload, ["Case_Id__c"]);
    const accountId = extractStringField(payload, ["Account_Id__c"]);

    if (!caseId) {
      this.logger.warn("Case event missing Case_Id__c", { channel });
      return;
    }

    this.logger.log("Case platform event received", {
      channel,
      caseIdTail: caseId.slice(-4),
      accountIdTail: accountId?.slice(-4),
    });

    await this.supportCache.invalidateCaseMessages(caseId);

    if (accountId) {
      await this.supportCache.invalidateCaseList(accountId);

      this.realtime.publish(`account:sf:${accountId}`, "support.case.changed", {
        caseId,
        timestamp: new Date().toISOString(),
      });
    }
  }
}
