import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, MoreThan } from 'typeorm';
import { AggregatedMetric, MetricType, TimeGranularity } from '../entities/aggregated-metric.entity';

export interface RealtimeMetric {
  metric: string;
  value: number;
  change: number;
  changePercent: number;
  timestamp: Date;
}

@Injectable()
export class MetricsService {
  constructor(
    @InjectRepository(AggregatedMetric)
    private readonly metricsRepository: Repository<AggregatedMetric>,
  ) {}

  async getRealtimeMetrics(metricNames: string[]): Promise<RealtimeMetric[]> {
    const now = new Date();
    const oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000);
    const twoHoursAgo = new Date(now.getTime() - 2 * 60 * 60 * 1000);

    const results: RealtimeMetric[] = [];

    for (const metricName of metricNames) {
      // Get current hour's data
      const currentData = await this.metricsRepository.findOne({
        where: {
          metricType: metricName as MetricType,
          granularity: TimeGranularity.HOUR,
          timestamp: MoreThan(oneHourAgo),
        },
        order: { timestamp: 'DESC' },
      });

      // Get previous hour's data for comparison
      const previousData = await this.metricsRepository.findOne({
        where: {
          metricType: metricName as MetricType,
          granularity: TimeGranularity.HOUR,
          timestamp: MoreThan(twoHoursAgo),
        },
        order: { timestamp: 'DESC' },
      });

      const currentValue = currentData ? Number(currentData.value) : 0;
      const previousValue = previousData ? Number(previousData.value) : 0;
      const change = currentValue - previousValue;
      const changePercent = previousValue > 0 ? (change / previousValue) * 100 : 0;

      results.push({
        metric: metricName,
        value: currentValue,
        change,
        changePercent,
        timestamp: now,
      });
    }

    return results;
  }

  async getActiveUsers(): Promise<number> {
    // Count unique sessions in the last 5 minutes from SESSIONS metric
    const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);

    const result = await this.metricsRepository
      .createQueryBuilder('m')
      .select('SUM(m.count)', 'total')
      .where('m.metricType = :type', { type: MetricType.SESSIONS })
      .andWhere('m.granularity = :gran', { gran: TimeGranularity.MINUTE })
      .andWhere('m.timestamp > :since', { since: fiveMinutesAgo })
      .getRawOne();

    return Number(result?.total ?? 0);
  }

  async getCurrentPageViews(): Promise<number> {
    const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);

    const result = await this.metricsRepository
      .createQueryBuilder('m')
      .select('SUM(m.count)', 'total')
      .where('m.metricType = :type', { type: MetricType.PAGE_VIEWS })
      .andWhere('m.granularity = :gran', { gran: TimeGranularity.MINUTE })
      .andWhere('m.timestamp > :since', { since: fiveMinutesAgo })
      .getRawOne();

    return Number(result?.total ?? 0);
  }
}
