// ============================================================
// CRM Event Publisher - Redis Pub/Sub
// ============================================================

import { Injectable, Logger } from '@nestjs/common';
import { RedisService } from '../redis/redis.service';

export interface CrmEvent {
  type: string;
  tenantId: string;
  entityId: string;
  userId: string;
  timestamp: string;
  payload: Record<string, unknown>;
}

@Injectable()
export class CrmEventPublisher {
  private readonly logger = new Logger(CrmEventPublisher.name);

  constructor(private readonly redis: RedisService) {}

  /**
   * Generische Publish-Methode.
   * Channel-Format: app:crm:events:{type}
   */
  private async publish(event: CrmEvent): Promise<void> {
    const channel = `app:crm:events:${event.type}`;
    try {
      const receivers = await this.redis.publish(channel, event as unknown as Record<string, unknown>);
      this.logger.debug(
        `Event "${event.type}" publiziert auf "${channel}" (${receivers} Empfaenger)`,
      );
    } catch (err) {
      this.logger.error(
        `Fehler beim Publizieren von Event "${event.type}": ${String(err)}`,
      );
    }
  }

  // --------------------------------------------------------
  // Contact Events
  // --------------------------------------------------------

  async contactCreated(tenantId: string, contactId: string, userId: string): Promise<void> {
    await this.publish({
      type: 'crm.contact.created',
      tenantId,
      entityId: contactId,
      userId,
      timestamp: new Date().toISOString(),
      payload: {},
    });
  }

  async contactUpdated(
    tenantId: string,
    contactId: string,
    userId: string,
    payload: Record<string, unknown> = {},
  ): Promise<void> {
    await this.publish({
      type: 'crm.contact.updated',
      tenantId,
      entityId: contactId,
      userId,
      timestamp: new Date().toISOString(),
      payload,
    });
  }

  // --------------------------------------------------------
  // Company Events
  // --------------------------------------------------------

  async companyCreated(tenantId: string, companyId: string, userId: string): Promise<void> {
    await this.publish({
      type: 'crm.company.created',
      tenantId,
      entityId: companyId,
      userId,
      timestamp: new Date().toISOString(),
      payload: {},
    });
  }

  async companyUpdated(
    tenantId: string,
    companyId: string,
    userId: string,
    payload: Record<string, unknown> = {},
  ): Promise<void> {
    await this.publish({
      type: 'crm.company.updated',
      tenantId,
      entityId: companyId,
      userId,
      timestamp: new Date().toISOString(),
      payload,
    });
  }

  // --------------------------------------------------------
  // Deal Events
  // --------------------------------------------------------

  async dealCreated(tenantId: string, dealId: string, userId: string): Promise<void> {
    await this.publish({
      type: 'crm.deal.created',
      tenantId,
      entityId: dealId,
      userId,
      timestamp: new Date().toISOString(),
      payload: {},
    });
  }

  async dealStageChanged(
    tenantId: string,
    dealId: string,
    userId: string,
    payload: { previousStageId: string; newStageId: string },
  ): Promise<void> {
    await this.publish({
      type: 'crm.deal.stage_changed',
      tenantId,
      entityId: dealId,
      userId,
      timestamp: new Date().toISOString(),
      payload,
    });
  }

  async dealWon(
    tenantId: string,
    dealId: string,
    userId: string,
    payload: { value?: number | null; currency?: string },
  ): Promise<void> {
    await this.publish({
      type: 'crm.deal.won',
      tenantId,
      entityId: dealId,
      userId,
      timestamp: new Date().toISOString(),
      payload,
    });
  }

  async dealLost(
    tenantId: string,
    dealId: string,
    userId: string,
    payload: { lostReason?: string | null },
  ): Promise<void> {
    await this.publish({
      type: 'crm.deal.lost',
      tenantId,
      entityId: dealId,
      userId,
      timestamp: new Date().toISOString(),
      payload,
    });
  }

  // --------------------------------------------------------
  // Activity Events
  // --------------------------------------------------------

  async activityDueSoon(
    tenantId: string,
    activityId: string,
    payload: { scheduledAt: string; contactId?: string; dealId?: string },
  ): Promise<void> {
    await this.publish({
      type: 'crm.activity.due_soon',
      tenantId,
      entityId: activityId,
      userId: 'system',
      timestamp: new Date().toISOString(),
      payload,
    });
  }
}
