import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Visitor } from '../entities/Visitor';
import { v4 as uuidv4 } from 'uuid';

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

  constructor(
    @InjectRepository(Visitor)
    private visitorRepository: Repository<Visitor>,
  ) {}

  /**
   * 跟踪访客访问
   * @param ip 访客IP地址
   * @param userAgent 用户代理
   * @param referrer 来源URL
   * @param page 访问页面
   * @returns 访客ID
   */
  async trackVisit(
    ip: string,
    userAgent: string,
    referrer: string,
    page: string,
  ): Promise<string> {
    try {
      const visitorId = uuidv4();
      const visitor = this.visitorRepository.create({
        id: visitorId,
        ip,
        userAgent,
        referrer,
        page,
        visitedAt: new Date(),
      });

      await this.visitorRepository.save(visitor);
      this.logger.log(`Tracked visitor: ${visitorId} visiting ${page}`);
      return visitorId;
    } catch (error) {
      this.logger.error('Failed to track visitor', error);
      throw error;
    }
  }

  /**
   * 获取访客统计
   * @param startDate 开始日期
   * @param endDate 结束日期
   * @returns 统计数据
   */
  async getVisitorStats(
    startDate: Date,
    endDate: Date,
  ): Promise<{
    totalVisitors: number;
    uniqueVisitors: number;
    pageViews: number;
    referrers: Array<{ referrer: string; count: number }>;
    pages: Array<{ page: string; count: number }>;
  }> {
    try {
      const [totalVisitors, uniqueVisitors, pageViews, referrers, pages] = await Promise.all([
        this.visitorRepository.count({
          where: {
            visitedAt: {
              between: [startDate, endDate],
            },
          },
        }),
        this.visitorRepository
          .createQueryBuilder('visitor')
          .select('COUNT(DISTINCT visitor.ip)', 'count')
          .where('visitor.visitedAt BETWEEN :startDate AND :endDate', { startDate, endDate })
          .getRawOne()
          .then((result) => parseInt(result.count, 10)),
        this.visitorRepository
          .createQueryBuilder('visitor')
          .select('COUNT(*)', 'count')
          .where('visitor.visitedAt BETWEEN :startDate AND :endDate', { startDate, endDate })
          .getRawOne()
          .then((result) => parseInt(result.count, 10)),
        this.visitorRepository
          .createQueryBuilder('visitor')
          .select('visitor.referrer, COUNT(*) as count')
          .where('visitor.visitedAt BETWEEN :startDate AND :endDate', { startDate, endDate })
          .groupBy('visitor.referrer')
          .orderBy('count', 'DESC')
          .limit(10)
          .getRawMany(),
        this.visitorRepository
          .createQueryBuilder('visitor')
          .select('visitor.page, COUNT(*) as count')
          .where('visitor.visitedAt BETWEEN :startDate AND :endDate', { startDate, endDate })
          .groupBy('visitor.page')
          .orderBy('count', 'DESC')
          .limit(10)
          .getRawMany(),
      ]);

      return {
        totalVisitors,
        uniqueVisitors,
        pageViews,
        referrers: referrers.map((r) => ({ referrer: r.referrer, count: parseInt(r.count, 10) })),
        pages: pages.map((p) => ({ page: p.page, count: parseInt(p.count, 10) })),
      };
    } catch (error) {
      this.logger.error('Failed to get visitor stats', error);
      throw error;
    }
  }

  /**
   * 清理旧访客数据
   * @param days 保留天数
   * @returns 删除的记录数
   */
  async cleanOldVisitors(days: number = 30): Promise<number> {
    try {
      const cutoffDate = new Date();
      cutoffDate.setDate(cutoffDate.getDate() - days);

      const result = await this.visitorRepository.delete({
        visitedAt: {
          lessThan: cutoffDate,
        },
      });

      this.logger.log(`Cleaned ${result.affected} old visitor records`);
      return result.affected || 0;
    } catch (error) {
      this.logger.error('Failed to clean old visitors', error);
      throw error;
    }
  }
}
