import { BadRequestException, Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '../infra/prisma.service';
import { MinioService } from '../infra/minio.service';
import { SettingsService } from './settings.service';

export const ADMIN_INSIGHTS_RETENTION_DAYS_KEY = 'ADMIN_INSIGHTS_RETENTION_DAYS';
export const DEFAULT_ADMIN_INSIGHTS_RETENTION_DAYS = 7;

const MODERATABLE_ROOM_FILTER = {
  isE2E: false,
  type: { notIn: ['E2E', 'BOT'] as string[] }
};

export interface AdminInsightsDateRange {
  from: Date;
  to: Date;
  retentionDays: number;
}

export interface AdminInsightsQueryOptions {
  search?: string;
  limit?: number;
  offset?: number;
  dateFrom?: string;
  dateTo?: string;
  beforeMessageId?: string;
}

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

  constructor(
    private readonly prisma: PrismaService,
    private readonly settings: SettingsService,
    private readonly minio: MinioService
  ) {}

  async getRetentionDays(): Promise<number> {
    const days = await this.settings.getNumber(ADMIN_INSIGHTS_RETENTION_DAYS_KEY, DEFAULT_ADMIN_INSIGHTS_RETENTION_DAYS);
    return Math.min(Math.max(Math.trunc(days), 1), 90);
  }

  getRetentionCutoff(retentionDays: number): Date {
    const cutoff = new Date();
    cutoff.setDate(cutoff.getDate() - retentionDays);
    cutoff.setMilliseconds(0);
    return cutoff;
  }

  private parseDateInput(value: string | undefined, label: string): Date | undefined {
    if (!value?.trim()) return undefined;
    const parsed = new Date(value.trim());
    if (Number.isNaN(parsed.getTime())) {
      throw new BadRequestException(`Некорректная дата ${label}`);
    }
    return parsed;
  }

  async resolveDateRange(dateFrom?: string, dateTo?: string): Promise<AdminInsightsDateRange> {
    const retentionDays = await this.getRetentionDays();
    const cutoff = this.getRetentionCutoff(retentionDays);
    const now = new Date();

    let from = this.parseDateInput(dateFrom, 'dateFrom') ?? cutoff;
    let to = this.parseDateInput(dateTo, 'dateTo') ?? now;

    if (from < cutoff) from = cutoff;
    if (to > now) to = now;
    if (from > to) {
      throw new BadRequestException('Дата начала не может быть позже даты окончания');
    }

    return { from, to, retentionDays };
  }

  createdAtFilter(range: AdminInsightsDateRange) {
    return { gte: range.from, lte: range.to };
  }

  insightsMeta(range: AdminInsightsDateRange) {
    return {
      retentionDays: range.retentionDays,
      periodFrom: range.from.toISOString(),
      periodTo: range.to.toISOString()
    };
  }

  async purgeExpiredInsights(): Promise<{ signInEvents: number; activityLogs: number; chatMessages: number }> {
    const retentionDays = await this.getRetentionDays();
    const cutoff = this.getRetentionCutoff(retentionDays);

    const signInResult = await this.prisma.signInEvent.deleteMany({
      where: { createdAt: { lt: cutoff } }
    });

    const activityResult = await this.prisma.userActivityLog.deleteMany({
      where: { createdAt: { lt: cutoff } }
    });

    let chatMessages = 0;
    const batchSize = 500;
    while (true) {
      const staleMessages = await this.prisma.chatMessage.findMany({
        where: {
          createdAt: { lt: cutoff },
          room: MODERATABLE_ROOM_FILTER
        },
        select: { id: true, storageKey: true },
        take: batchSize
      });
      if (!staleMessages.length) break;

      const storageKeys = staleMessages.map((item) => item.storageKey).filter((key): key is string => Boolean(key));
      if (storageKeys.length) {
        await this.minio.deleteObjects(storageKeys);
      }

      const deleted = await this.prisma.chatMessage.deleteMany({
        where: { id: { in: staleMessages.map((item) => item.id) } }
      });
      chatMessages += deleted.count;
      if (staleMessages.length < batchSize) break;
    }

    if (signInResult.count || activityResult.count || chatMessages) {
      this.logger.log(
        `Очистка журналов (${retentionDays} дн.): входы=${signInResult.count}, активность=${activityResult.count}, чаты=${chatMessages}`
      );
    }

    return {
      signInEvents: signInResult.count,
      activityLogs: activityResult.count,
      chatMessages
    };
  }
}
