import fetch from 'node-fetch';
import { TimeManager } from '../../../shared/business-time/index.js';
import { RedisService } from './redis.service.js';

const METRIC_IDS = {
  PLACED_ORDER: 'Y8cqcF'
};

export class ReportingService {
  constructor(apiKey, apiRevision, redis) {
    this.apiKey = apiKey;
    this.apiRevision = apiRevision;
    this.baseUrl = 'https://a.klaviyo.com/api';
    this.timeManager = new TimeManager();
    this.redisService = new RedisService(redis);
    this._pendingReportRequest = null;
  }

  async getCampaignReports(params = {}) {
    try {
      // Check if there's a pending request
      if (this._pendingReportRequest) {
        console.log('[ReportingService] Using pending campaign report request');
        return this._pendingReportRequest;
      }

      // Try to get from cache first
      const cacheKey = this.redisService._getCacheKey('campaign_reports', params);
      let cachedData = null;
      try {
        cachedData = await this.redisService.get(`${cacheKey}:raw`);
        if (cachedData) {
          console.log('[ReportingService] Using cached campaign report data');
          return cachedData;
        }
      } catch (cacheError) {
        console.warn('[ReportingService] Cache error:', cacheError);
      }

      // Create new request promise
      this._pendingReportRequest = (async () => {
        console.log('[ReportingService] Fetching fresh campaign report data');

        const range = this.timeManager.getDateRange(params.timeRange || 'last30days');
        
        // Determine which channels to fetch based on params
        const channelsToFetch = params.channel === 'all' || !params.channel
          ? ['email', 'sms']
          : [params.channel];

        const allResults = [];
        
        // Fetch each channel
        for (const channel of channelsToFetch) {
          const payload = {
            data: {
              type: "campaign-values-report",
              attributes: {
                timeframe: {
                  start: range.start.toISO(),
                  end: range.end.toISO()
                },
                statistics: [
                  "delivery_rate",
                  "delivered",
                  "recipients",
                  "open_rate",
                  "opens_unique",
                  "opens",
                  "click_rate",
                  "clicks_unique",
                  "click_to_open_rate",
                  "conversion_value",
                  "conversion_uniques"
                ],
                conversion_metric_id: METRIC_IDS.PLACED_ORDER,
                filter: `equals(send_channel,"${channel}")`
              }
            }
          };

          const response = await fetch(`${this.baseUrl}/campaign-values-reports`, {
            method: 'POST',
            headers: {
              'Accept': 'application/json',
              'Content-Type': 'application/json',
              'Authorization': `Klaviyo-API-Key ${this.apiKey}`,
              'revision': this.apiRevision
            },
            body: JSON.stringify(payload)
          });

          if (!response.ok) {
            const errorData = await response.json();
            console.error('[ReportingService] API Error:', errorData);
            throw new Error(`Klaviyo API error: ${response.status} ${response.statusText}`);
          }

          const reportData = await response.json();
          console.log(`[ReportingService] Raw ${channel} report data:`, JSON.stringify(reportData, null, 2));
          
          // Get campaign IDs from the report
          const campaignIds = reportData.data?.attributes?.results?.map(result => 
            result.groupings?.campaign_id
          ).filter(Boolean) || [];
          
          if (campaignIds.length > 0) {
            // Get campaign details including send time and subject lines
            const campaignDetails = await this.getCampaignDetails(campaignIds);
            
            // Process results for this channel
            const channelResults = reportData.data.attributes.results.map(result => {
              const campaignId = result.groupings.campaign_id;
              const details = campaignDetails.find(detail => detail.id === campaignId);

              return {
                id: campaignId,
                name: details.attributes.name,
                subject: details.attributes.subject,
                send_time: details.attributes.send_time,
                channel: channel, // Use the channel we're currently processing
                stats: {
                  delivery_rate: result.statistics.delivery_rate,
                  delivered: result.statistics.delivered,
                  recipients: result.statistics.recipients,
                  open_rate: result.statistics.open_rate,
                  opens_unique: result.statistics.opens_unique,
                  opens: result.statistics.opens,
                  click_rate: result.statistics.click_rate,
                  clicks_unique: result.statistics.clicks_unique,
                  click_to_open_rate: result.statistics.click_to_open_rate,
                  conversion_value: result.statistics.conversion_value,
                  conversion_uniques: result.statistics.conversion_uniques
                }
              };
            });

            allResults.push(...channelResults);
          }
        }

        // Sort all results by date
        const enrichedData = {
          data: allResults.sort((a, b) => {
            const dateA = new Date(a.send_time);
            const dateB = new Date(b.send_time);
            return dateB - dateA; // Sort by date descending
          })
        };

        console.log('[ReportingService] Enriched data:', JSON.stringify(enrichedData, null, 2));

        // Cache the enriched response for 10 minutes
        try {
          await this.redisService.set(`${cacheKey}:raw`, enrichedData, 600);
        } catch (cacheError) {
          console.warn('[ReportingService] Cache set error:', cacheError);
        }

        return enrichedData;
      })();

      const result = await this._pendingReportRequest;
      this._pendingReportRequest = null;
      return result;

    } catch (error) {
      console.error('[ReportingService] Error fetching campaign reports:', error);
      this._pendingReportRequest = null;
      throw error;
    }
  }

  async getCampaignDetails(campaignIds = []) {
    if (!Array.isArray(campaignIds) || campaignIds.length === 0) {
      return [];
    }

    const fetchWithTimeout = async (campaignId, retries = 3) => {
      for (let i = 0; i < retries; i++) {
        try {
          const controller = new AbortController();
          const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 second timeout

          const response = await fetch(
            `${this.baseUrl}/campaigns/${campaignId}?include=campaign-messages`,
            {
              headers: {
                'Accept': 'application/json',
                'Authorization': `Klaviyo-API-Key ${this.apiKey}`,
                'revision': this.apiRevision
              },
              signal: controller.signal
            }
          );

          clearTimeout(timeoutId);

          if (!response.ok) {
            throw new Error(`Failed to fetch campaign ${campaignId}: ${response.status}`);
          }

          const data = await response.json();
          if (!data.data) {
            throw new Error(`Invalid response for campaign ${campaignId}`);
          }

          const message = data.included?.find(item => item.type === 'campaign-message');
          
          console.log('[ReportingService] Campaign details for ID:', campaignId, {
            send_channel: data.data.attributes.send_channel,
            raw_attributes: data.data.attributes
          });

          return {
            id: data.data.id,
            type: data.data.type,
            attributes: {
              ...data.data.attributes,
              name: data.data.attributes.name,
              send_time: data.data.attributes.send_time,
              subject: message?.attributes?.content?.subject,
              send_channel: data.data.attributes.send_channel || 'email'
            }
          };
        } catch (error) {
          if (i === retries - 1) throw error;
          await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); // Exponential backoff
        }
      }
    };

    // Process in smaller chunks to avoid overwhelming the API
    const chunkSize = 10;
    const campaignDetails = [];
    
    for (let i = 0; i < campaignIds.length; i += chunkSize) {
      const chunk = campaignIds.slice(i, i + chunkSize);
      const results = await Promise.all(
        chunk.map(id => fetchWithTimeout(id).catch(error => {
          console.error(`Failed to fetch campaign ${id}:`, error);
          return null;
        }))
      );
      campaignDetails.push(...results.filter(Boolean));
      
      if (i + chunkSize < campaignIds.length) {
        await new Promise(resolve => setTimeout(resolve, 1000)); // 1 second delay between chunks
      }
    }

    return campaignDetails;
  }
} 