// Klaviyo cache wrapper. Was a self-instantiating ioredis client per service in
// the standalone klaviyo-server; now accepts an injected client so the merged
// dashboard-server shares one connection across all vendors (Phase 4).
//
// Public surface kept identical to the original so the ~3K LOC of klaviyo
// service code (events/campaigns/reporting) needs no other changes:
//   - get(key)
//   - set(key, data, ttl)
//   - _getCacheKey(type, params)
//   - _getTTL(timeRange)
//   - getEventData(type, params) / cacheEventData(type, params, data)
//   - clearCache(params)
//
// Reads short-circuit to null when the client isn't ready; writes are no-ops.
// Same "Redis hiccup → fall through to upstream" behavior as before.

import { TimeManager } from '../../../shared/business-time/index.js';

export class RedisService {
  constructor(redis) {
    if (!redis) {
      throw new Error('RedisService requires an ioredis client (Phase 4: injected, no longer self-constructed)');
    }
    this.client = redis;
    this.timeManager = new TimeManager();
    this.DEFAULT_TTL = 5 * 60;
  }

  get isConnected() {
    // ioredis: 'wait' | 'reconnecting' | 'connecting' | 'connect' | 'ready' | 'close' | 'end'
    return this.client.status === 'ready' || this.client.status === 'connect';
  }

  async get(key) {
    if (!this.isConnected) return null;
    try {
      const data = await this.client.get(key);
      return data ? JSON.parse(data) : null;
    } catch (error) {
      console.error('[RedisService] Error getting data:', error);
      return null;
    }
  }

  async set(key, data, ttl = this.DEFAULT_TTL) {
    if (!this.isConnected) return;
    try {
      await this.client.setex(key, ttl, JSON.stringify(data));
    } catch (error) {
      console.error('[RedisService] Error setting data:', error);
    }
  }

  _getCacheKey(type, params = {}) {
    const {
      timeRange,
      startDate,
      endDate,
      metricId,
      metric,
      daily,
      cacheKey,
      isPreviousPeriod,
      customFilters,
    } = params;

    let key = `klaviyo:${type}`;

    if (type === 'stats:details') {
      key += `:${metric || 'all'}`;
      if (daily) key += ':daily';
      if (customFilters?.length) {
        const filterHash = customFilters.join('').replace(/[^a-zA-Z0-9]/g, '');
        key += `:${filterHash}`;
      }
    }

    if (cacheKey) {
      key += `:${cacheKey}`;
    } else if (timeRange) {
      key += `:${timeRange}`;
      if (metricId) key += `:${metricId}`;
      if (isPreviousPeriod) key += ':prev';
    } else if (startDate && endDate) {
      key += `:custom:${startDate}:${endDate}`;
      if (metricId) key += `:${metricId}`;
      if (isPreviousPeriod) key += ':prev';
    }

    if (['pre_orders', 'local_pickup', 'on_hold'].includes(metric)) {
      key += `:${metric}`;
    }

    return key;
  }

  _getTTL(timeRange) {
    const TTL_MAP = {
      today: 2 * 60,
      yesterday: 30 * 60,
      thisWeek: 5 * 60,
      lastWeek: 60 * 60,
      thisMonth: 10 * 60,
      lastMonth: 2 * 60 * 60,
      last7days: 5 * 60,
      last30days: 15 * 60,
      custom: 15 * 60,
    };
    return TTL_MAP[timeRange] || this.DEFAULT_TTL;
  }

  async getEventData(type, params) {
    if (!this.isConnected) return null;
    try {
      const baseKey = this._getCacheKey('events', params);
      return await this.get(`${baseKey}:${type}`);
    } catch (error) {
      console.error('[RedisService] Error getting event data:', error);
      return null;
    }
  }

  async cacheEventData(type, params, data) {
    if (!this.isConnected) return;
    try {
      const ttl = this._getTTL(params.timeRange);
      const baseKey = this._getCacheKey('events', params);
      await this.set(`${baseKey}:${type}`, data, ttl);
    } catch (error) {
      console.error('[RedisService] Error caching event data:', error);
    }
  }

  async clearCache(params = {}) {
    if (!this.isConnected) return;
    try {
      const pattern = this._getCacheKey('events', params) + '*';
      const keys = await this.client.keys(pattern);
      if (keys.length > 0) {
        await this.client.del(...keys);
      }
    } catch (error) {
      console.error('[RedisService] Error clearing cache:', error);
    }
  }
}
