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

export class CampaignsService {
  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);
  }

  async getCampaigns(params = {}) {
    try {
      // Add request debouncing
      const requestKey = JSON.stringify(params);
      if (this._pendingRequests && this._pendingRequests[requestKey]) {
        return this._pendingRequests[requestKey];
      }

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

      this._pendingRequests = this._pendingRequests || {};
      this._pendingRequests[requestKey] = (async () => {
        let allCampaigns = [];
        let nextCursor = params.pageCursor;
        let pageCount = 0;
        
        const filter = params.filter || this._buildFilter(params);
        
        do {
          const queryParams = new URLSearchParams();
          if (filter) {
            queryParams.append('filter', filter);
          }
          queryParams.append('sort', params.sort || '-send_time');

          if (nextCursor) {
            queryParams.append('page[cursor]', nextCursor);
          }

          const url = `${this.baseUrl}/campaigns?${queryParams.toString()}`;

          try {
            const response = await fetch(url, {
              method: 'GET',
              headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                'Authorization': `Klaviyo-API-Key ${this.apiKey}`,
                'revision': this.apiRevision
              }
            });

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

            const responseData = await response.json();
            allCampaigns = allCampaigns.concat(responseData.data || []);
            pageCount++;
            
            nextCursor = responseData.links?.next ? 
              new URL(responseData.links.next).searchParams.get('page[cursor]') : null;

            if (nextCursor) {
              await new Promise(resolve => setTimeout(resolve, 50));
            }
          } catch (fetchError) {
            console.error('[CampaignsService] Fetch error:', fetchError);
            throw fetchError;
          }
          
        } while (nextCursor);

        const transformedCampaigns = this._transformCampaigns(allCampaigns);

        const result = {
          data: transformedCampaigns,
          meta: {
            total_count: transformedCampaigns.length,
            page_count: pageCount
          }
        };

        try {
          const ttl = this.redisService._getTTL(params.timeRange);
          await this.redisService.set(`${cacheKey}:raw`, result, ttl);
        } catch (cacheError) {
          console.warn('[CampaignsService] Cache set error:', cacheError);
        }

        delete this._pendingRequests[requestKey];
        return result;
      })();

      return await this._pendingRequests[requestKey];
    } catch (error) {
      console.error('[CampaignsService] Error fetching campaigns:', error);
      throw error;
    }
  }

  _buildFilter(params) {
    const filters = [];
    
    if (params.startDate && params.endDate) {
      const startUtc = this.timeManager.formatForAPI(params.startDate);
      const endUtc = this.timeManager.formatForAPI(params.endDate);
      
      filters.push(`greater-or-equal(send_time,${startUtc})`);
      filters.push(`less-than(send_time,${endUtc})`);
    }

    if (params.status) {
      filters.push(`equals(status,"${params.status}")`);
    }

    if (params.customFilters) {
      filters.push(...params.customFilters);
    }

    return filters.length > 0 ? (filters.length > 1 ? `and(${filters.join(',')})` : filters[0]) : null;
  }

  async getCampaignsByTimeRange(timeRange, options = {}) {
    const range = this.timeManager.getDateRange(timeRange);
    if (!range) {
      throw new Error('Invalid time range specified');
    }

    const params = {
      timeRange,
      startDate: range.start.toISO(),
      endDate: range.end.toISO(),
      ...options
    };

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

    return this.getCampaigns(params);
  }

  _transformCampaigns(campaigns) {
    if (!Array.isArray(campaigns)) {
      console.warn('[CampaignsService] Campaigns is not an array:', campaigns);
      return [];
    }

    return campaigns.map(campaign => {
      try {
        const stats = campaign.attributes?.campaign_message?.stats || {};
        
        return {
          id: campaign.id,
          name: campaign.attributes?.name || "Unnamed Campaign",
          subject: campaign.attributes?.campaign_message?.subject || "",
          send_time: campaign.attributes?.send_time,
          stats: {
            delivery_rate: stats.delivery_rate || 0,
            delivered: stats.delivered || 0,
            recipients: stats.recipients || 0,
            open_rate: stats.open_rate || 0,
            opens_unique: stats.opens_unique || 0,
            opens: stats.opens || 0,
            clicks_unique: stats.clicks_unique || 0,
            click_rate: stats.click_rate || 0,
            click_to_open_rate: stats.click_to_open_rate || 0,
            conversion_value: stats.conversion_value || 0,
            conversion_uniques: stats.conversion_uniques || 0
          }
        };
      } catch (error) {
        console.error('[CampaignsService] Error transforming campaign:', error, campaign);
        return {
          id: campaign.id || 'unknown',
          name: 'Error Processing Campaign',
          stats: {}
        };
      }
    });
  }
} 