import { Injectable, NotFoundException, Logger, Optional } from '@nestjs/common';
import { NotificationsRepository } from './notifications.repository';
import { EventBusService } from '../../common/event-bus/event-bus.service';
import { NotificationSentEvent } from '../../common/events/notification-sent.event';
import { NotificationReadEvent } from '../../common/events/notification-read.event';
import { NotificationPreferenceChangedEvent } from '../../common/events/notification-preference-changed.event';
import type { PaginationDto } from '../../common/dto/pagination.dto';

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

  constructor(
    private readonly repository: NotificationsRepository,
    @Optional() private readonly eventBus?: EventBusService,
  ) {}

  // ═══ Notifications ═══

  async list(userId: string, pagination: PaginationDto) {
    const [items, unreadCount] = await Promise.all([
      this.repository.findAll(userId, pagination),
      this.repository.countUnread(userId),
    ]);
    return { items, unreadCount };
  }

  async markRead(userId: string, id: string) {
    const notification = await this.repository.findById(id);
    if (!notification) throw new NotFoundException(`Notification ${id} not found`);

    await this.repository.markRead(id);

    try { this.eventBus?.publish(new NotificationReadEvent(userId, id)); } catch {}

    return { ok: true };
  }

  async markAllRead(userId: string) {
    await this.repository.markAllRead(userId);
    return { ok: true };
  }

  async send(data: { userId: string; type: string; title: string; body: string }) {
    const notification = await this.repository.create(data);
    this.logger.log(`Notification ${notification.id} sent to user ${data.userId}`);

    try { this.eventBus?.publish(new NotificationSentEvent(data.userId, notification.id, data.type, 'in_app')); } catch {}

    return notification;
  }

  // ═══ Preferences ═══

  async getPreferences(userId: string) {
    return this.repository.getPreference(userId);
  }

  async updatePreferences(userId: string, dto: Record<string, any>) {
    const updated = await this.repository.updatePreference(userId, dto);

    try { this.eventBus?.publish(new NotificationPreferenceChangedEvent(userId, dto)); } catch {}

    return updated;
  }

  // ═══ Push Tokens ═══

  async registerPushToken(userId: string, token: string, platform: string, deviceId?: string) {
    return this.repository.registerPushToken(userId, token, platform, deviceId);
  }

  async getPushTokens(userId: string) {
    return this.repository.findPushTokens(userId);
  }

  async removePushToken(userId: string, token: string) {
    await this.repository.removePushToken(userId, token);
    return { ok: true };
  }

  // ═══ Templates (Admin) ═══

  async getTemplates() {
    return this.repository.findTemplates();
  }

  async createTemplate(dto: { name: string; type: string; title: string; content: string; channel?: string }, createdBy?: string) {
    return this.repository.createTemplate({ ...dto, createdBy });
  }

  async updateTemplate(id: string, dto: Record<string, any>) {
    const tpl = await this.repository.findTemplateById(id);
    if (!tpl) throw new NotFoundException('模板不存在');
    return this.repository.updateTemplate(id, dto);
  }

  async deleteTemplate(id: string) {
    const tpl = await this.repository.findTemplateById(id);
    if (!tpl) throw new NotFoundException('模板不存在');
    return this.repository.deleteTemplate(id);
  }

  // ═══ Admin send log ═══

  async getSendLogs(limit = 100) {
    return this.repository.findRecentSent(limit);
  }
}
