import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '../../../prisma/prisma.service';
import { TgUser, TgChat } from './telegram-api.service';

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

  constructor(private readonly prisma: PrismaService) {}

  /**
   * Find or create a subscriber when a user interacts with the bot.
   * Returns { subscriber, isNew }.
   */
  async findOrCreate(
    botId: string,
    clubId: string,
    chat: TgChat,
    from?: TgUser,
    source?: string,
    referrerId?: string,
  ) {
    const chatId = String(chat.id);

    const existing = await this.prisma.tgBotSubscriber.findUnique({
      where: { botId_chatId: { botId, chatId } },
    });

    if (existing) {
      // Update lastActiveAt and re-subscribe if blocked
      const updates: Record<string, unknown> = { lastActiveAt: new Date() };
      if (existing.blockedAt) {
        updates.isSubscribed = true;
        updates.blockedAt = null;
      }

      const subscriber = await this.prisma.tgBotSubscriber.update({
        where: { id: existing.id },
        data: updates,
      });

      return { subscriber, isNew: false };
    }

    const subscriber = await this.prisma.tgBotSubscriber.create({
      data: {
        clubId,
        botId,
        chatId,
        telegramUserId: from ? String(from.id) : null,
        username: from?.username ?? null,
        firstName: from?.first_name ?? chat.first_name ?? null,
        lastName: from?.last_name ?? chat.last_name ?? null,
        source: source ?? null,
        referrerId: referrerId ?? null,
        isRegistered: true,
        registeredAt: new Date(),
        lastActiveAt: new Date(),
      },
    });

    // Increment referrer's invitedCount
    if (referrerId) {
      await this.prisma.tgBotSubscriber
        .update({
          where: { id: referrerId },
          data: { invitedCount: { increment: 1 } },
        })
        .catch((err: unknown) => {
          this.logger.warn(
            `Failed to increment referrer ${referrerId}: ${err instanceof Error ? err.message : String(err)}`,
          );
        });
    }

    return { subscriber, isNew: true };
  }

  async findByBotAndChat(botId: string, chatId: string) {
    return this.prisma.tgBotSubscriber.findUnique({
      where: { botId_chatId: { botId, chatId } },
    });
  }

  async updateState(
    subscriberId: string,
    currentNodeId: string | null,
    variables: Record<string, unknown>,
  ) {
    return this.prisma.tgBotSubscriber.update({
      where: { id: subscriberId },
      data: {
        currentNodeId,
        variables: variables as object,
        lastActiveAt: new Date(),
      },
    });
  }

  async updatePhone(subscriberId: string, phone: string) {
    return this.prisma.tgBotSubscriber.update({
      where: { id: subscriberId },
      data: { phone },
    });
  }

  async markUnsubscribed(botId: string, chatId: string) {
    const sub = await this.prisma.tgBotSubscriber.findUnique({
      where: { botId_chatId: { botId, chatId } },
    });
    if (!sub) return;

    await this.prisma.tgBotSubscriber.update({
      where: { id: sub.id },
      data: { isSubscribed: false, blockedAt: new Date() },
    });
  }

  async markBlocked(botId: string, chatId: string) {
    const sub = await this.prisma.tgBotSubscriber.findUnique({
      where: { botId_chatId: { botId, chatId } },
    });
    if (!sub) return;

    await this.prisma.tgBotSubscriber.update({
      where: { id: sub.id },
      data: { isSubscribed: false, blockedAt: new Date() },
    });
  }

  /** List subscribers with filters (for admin table) */
  async findAll(
    botId: string,
    params: {
      cursor?: string;
      limit?: number;
      search?: string;
      isSubscribed?: boolean;
      bonusGranted?: boolean;
      mailingConsent?: boolean;
    },
  ) {
    const { cursor, limit = 50, search, isSubscribed, bonusGranted, mailingConsent } = params;

    const where: Record<string, unknown> = { botId };
    if (isSubscribed !== undefined) where.isSubscribed = isSubscribed;
    if (bonusGranted !== undefined) where.bonusGranted = bonusGranted;
    if (mailingConsent !== undefined) where.mailingConsent = mailingConsent;
    if (search) {
      where.OR = [
        { firstName: { contains: search, mode: 'insensitive' } },
        { lastName: { contains: search, mode: 'insensitive' } },
        { username: { contains: search, mode: 'insensitive' } },
        { phone: { contains: search } },
      ];
    }

    const items = await this.prisma.tgBotSubscriber.findMany({
      where,
      take: limit + 1,
      ...(cursor ? { cursor: { id: cursor }, skip: 1 } : {}),
      orderBy: { createdAt: 'desc' },
    });

    const hasMore = items.length > limit;
    const data = hasMore ? items.slice(0, -1) : items;

    return {
      data,
      nextCursor: hasMore ? data[data.length - 1].id : null,
      hasMore,
    };
  }

  async getStats(botId: string) {
    const [total, subscribed, withPhone, bonusGranted, mailingConsent] = await Promise.all([
      this.prisma.tgBotSubscriber.count({ where: { botId } }),
      this.prisma.tgBotSubscriber.count({ where: { botId, isSubscribed: true } }),
      this.prisma.tgBotSubscriber.count({ where: { botId, phone: { not: null } } }),
      this.prisma.tgBotSubscriber.count({ where: { botId, bonusGranted: true } }),
      this.prisma.tgBotSubscriber.count({ where: { botId, mailingConsent: true } }),
    ]);

    return { total, subscribed, withPhone, bonusGranted, mailingConsent };
  }
}
