const { BetaAnalyticsDataClient } = require('@google-analytics/data');
const { createClient } = require('redis');

class AnalyticsService {
  constructor() {
    // Initialize Redis client
    this.redis = createClient({
      url: process.env.REDIS_URL || 'redis://localhost:6379'
    });
    
    this.redis.on('error', err => console.error('Redis Client Error:', err));
    this.redis.connect().catch(err => console.error('Redis connection error:', err));

    try {
      // Initialize GA4 client
      const credentials = process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON;
      this.analyticsClient = new BetaAnalyticsDataClient({
        credentials: typeof credentials === 'string' ? JSON.parse(credentials) : credentials
      });
      
      this.propertyId = process.env.GA_PROPERTY_ID;
    } catch (error) {
      console.error('Failed to initialize GA4 client:', error);
      throw error;
    }
  }

  // Cache durations
  CACHE_DURATIONS = {
    REALTIME_BASIC: 60, // 1 minute
    REALTIME_DETAILED: 300, // 5 minutes
    BASIC_METRICS: 3600, // 1 hour
    USER_BEHAVIOR: 3600 // 1 hour
  };

  async getBasicMetrics(startDate = '7daysAgo') {
    const cacheKey = `analytics:basic_metrics:${startDate}`;
    
    try {
      // Try Redis first
      const cachedData = await this.redis.get(cacheKey);
      if (cachedData) {
        console.log('Analytics metrics found in Redis cache');
        return JSON.parse(cachedData);
      }

      // Fetch from GA4
      console.log('Fetching fresh metrics data from GA4');
      const [response] = await this.analyticsClient.runReport({
        property: `properties/${this.propertyId}`,
        dateRanges: [{ startDate, endDate: 'today' }],
        dimensions: [{ name: 'date' }],
        metrics: [
          { name: 'activeUsers' },
          { name: 'newUsers' },
          { name: 'averageSessionDuration' },
          { name: 'screenPageViews' },
          { name: 'bounceRate' },
          { name: 'conversions' }
        ],
        returnPropertyQuota: true
      });

      // Cache the response
      await this.redis.set(cacheKey, JSON.stringify(response), {
        EX: this.CACHE_DURATIONS.BASIC_METRICS
      });

      return response;
    } catch (error) {
      console.error('Error fetching analytics metrics:', {
        error: error.message,
        stack: error.stack
      });
      throw error;
    }
  }

  async getRealTimeBasicData() {
    const cacheKey = 'analytics:realtime:basic';
    
    try {
      // Try Redis first
      const cachedData = await this.redis.get(cacheKey);
      if (cachedData) {
        console.log('Realtime basic data found in Redis cache');
        return JSON.parse(cachedData);
      }

      console.log('Fetching fresh realtime data from GA4');
      
      // Fetch active users
      const [userResponse] = await this.analyticsClient.runRealtimeReport({
        property: `properties/${this.propertyId}`,
        metrics: [{ name: 'activeUsers' }],
        returnPropertyQuota: true
      });

      // Fetch last 5 minutes
      const [fiveMinResponse] = await this.analyticsClient.runRealtimeReport({
        property: `properties/${this.propertyId}`,
        metrics: [{ name: 'activeUsers' }],
        minuteRanges: [{ startMinutesAgo: 5, endMinutesAgo: 0 }]
      });

      // Fetch time series data
      const [timeSeriesResponse] = await this.analyticsClient.runRealtimeReport({
        property: `properties/${this.propertyId}`,
        dimensions: [{ name: 'minutesAgo' }],
        metrics: [{ name: 'activeUsers' }]
      });

      const response = {
        userResponse,
        fiveMinResponse,
        timeSeriesResponse,
        quotaInfo: {
          projectHourly: userResponse.propertyQuota.tokensPerProjectPerHour,
          daily: userResponse.propertyQuota.tokensPerDay,
          serverErrors: userResponse.propertyQuota.serverErrorsPerProjectPerHour,
          thresholdedRequests: userResponse.propertyQuota.potentiallyThresholdedRequestsPerHour
        }
      };

      // Cache the response
      await this.redis.set(cacheKey, JSON.stringify(response), {
        EX: this.CACHE_DURATIONS.REALTIME_BASIC
      });

      return response;
    } catch (error) {
      console.error('Error fetching realtime basic data:', {
        error: error.message,
        stack: error.stack
      });
      throw error;
    }
  }

  async getRealTimeDetailedData() {
    const cacheKey = 'analytics:realtime:detailed';
    
    try {
      // Try Redis first
      const cachedData = await this.redis.get(cacheKey);
      if (cachedData) {
        console.log('Realtime detailed data found in Redis cache');
        return JSON.parse(cachedData);
      }

      console.log('Fetching fresh realtime detailed data from GA4');

      // Fetch current pages
      const [pageResponse] = await this.analyticsClient.runRealtimeReport({
        property: `properties/${this.propertyId}`,
        dimensions: [{ name: 'unifiedScreenName' }],
        metrics: [{ name: 'screenPageViews' }],
        orderBy: [{ metric: { metricName: 'screenPageViews' }, desc: true }],
        limit: 25
      });

      // Fetch events
      const [eventResponse] = await this.analyticsClient.runRealtimeReport({
        property: `properties/${this.propertyId}`,
        dimensions: [{ name: 'eventName' }],
        metrics: [{ name: 'eventCount' }],
        orderBy: [{ metric: { metricName: 'eventCount' }, desc: true }],
        limit: 25
      });

      // Fetch device categories
      const [deviceResponse] = await this.analyticsClient.runRealtimeReport({
        property: `properties/${this.propertyId}`,
        dimensions: [{ name: 'deviceCategory' }],
        metrics: [{ name: 'activeUsers' }],
        orderBy: [{ metric: { metricName: 'activeUsers' }, desc: true }],
        limit: 10,
        returnPropertyQuota: true
      });

      const response = {
        pageResponse,
        eventResponse,
        sourceResponse: deviceResponse
      };

      // Cache the response
      await this.redis.set(cacheKey, JSON.stringify(response), {
        EX: this.CACHE_DURATIONS.REALTIME_DETAILED
      });

      return response;
    } catch (error) {
      console.error('Error fetching realtime detailed data:', {
        error: error.message,
        stack: error.stack
      });
      throw error;
    }
  }

  async getUserBehavior(timeRange = '30') {
    const cacheKey = `analytics:user_behavior:${timeRange}`;
    
    try {
      // Try Redis first
      const cachedData = await this.redis.get(cacheKey);
      if (cachedData) {
        console.log('User behavior data found in Redis cache');
        return JSON.parse(cachedData);
      }

      console.log('Fetching fresh user behavior data from GA4');

      // Fetch page data
      const [pageResponse] = await this.analyticsClient.runReport({
        property: `properties/${this.propertyId}`,
        dateRanges: [{ startDate: `${timeRange}daysAgo`, endDate: 'today' }],
        dimensions: [{ name: 'pagePath' }],
        metrics: [
          { name: 'screenPageViews' },
          { name: 'averageSessionDuration' },
          { name: 'bounceRate' },
          { name: 'sessions' }
        ],
        orderBy: [{
          metric: { metricName: 'screenPageViews' },
          desc: true
        }],
        limit: 25
      });

      // Fetch device data
      const [deviceResponse] = await this.analyticsClient.runReport({
        property: `properties/${this.propertyId}`,
        dateRanges: [{ startDate: `${timeRange}daysAgo`, endDate: 'today' }],
        dimensions: [{ name: 'deviceCategory' }],
        metrics: [
          { name: 'screenPageViews' },
          { name: 'sessions' }
        ]
      });

      // Fetch source data
      const [sourceResponse] = await this.analyticsClient.runReport({
        property: `properties/${this.propertyId}`,
        dateRanges: [{ startDate: `${timeRange}daysAgo`, endDate: 'today' }],
        dimensions: [{ name: 'sessionSource' }],
        metrics: [
          { name: 'sessions' },
          { name: 'conversions' }
        ],
        orderBy: [{
          metric: { metricName: 'sessions' },
          desc: true
        }],
        limit: 25,
        returnPropertyQuota: true
      });

      const response = {
        pageResponse,
        deviceResponse,
        sourceResponse
      };

      // Cache the response
      await this.redis.set(cacheKey, JSON.stringify(response), {
        EX: this.CACHE_DURATIONS.USER_BEHAVIOR
      });

      return response;
    } catch (error) {
      console.error('Error fetching user behavior data:', {
        error: error.message,
        stack: error.stack
      });
      throw error;
    }
  }
}

module.exports = new AnalyticsService(); 