import { BaseProvider } from './BaseProvider';
import { updateGoogleConsent } from '../googleConsentMode';
import { EventBatcher } from '../EventBatcher';

export class GA4Provider extends BaseProvider {
  constructor(config = {}) {
    super(config);
    this.measurementId = config.measurementId;
    this.hasConsent = config.hasConsent || false;
    this.consentLocked = false;
    const envDebugMode = import.meta.env.VITE_GA4_DEBUG;
    this.debugMode =
      typeof config.debugMode === 'boolean'
        ? config.debugMode
        : envDebugMode === 'true'
          ? true
          : envDebugMode === 'false'
            ? false
            : import.meta.env.DEV;

    // Batching configuration
    this.batcher = new EventBatcher({
      batchSize: config.batchSize || 10,
      batchTimeout: config.batchTimeout || 30000,
      onBatch: (batch) => this.sendBatch(batch),
    });
  }

  async initialize() {
    if (!this.measurementId) {
      console.warn('GA4Provider: measurementId not provided');
      return;
    }

    if (!this.hasConsent) {
      return;
    }

    this.loadGA4Script();
    this.enabled = true;
  }

  loadGA4Script() {
    // Initialize dataLayer and gtag function
    window.dataLayer = window.dataLayer || [];

    window.gtag = function () {
      window.dataLayer.push(arguments);
    };

    // Configure gtag
    window.gtag('js', new Date());

    window.gtag('config', this.measurementId, {
      page_path: window.location.pathname,
      anonymize_ip: true,
      allow_google_signals: false,
      debug_mode: this.debugMode,
    });

    const scriptSrc = `https://www.googletagmanager.com/gtag/js?id=${this.measurementId}`;
    const existingScript = document.querySelector(`script[src="${scriptSrc}"]`);
    if (existingScript) {
      return;
    }

    // Load GA4 script
    const script = document.createElement('script');
    script.async = true;
    script.src = scriptSrc;

    script.onload = () => {};

    script.onerror = () => {
      console.error('❌ Failed to load GA4 script from Google');
    };

    document.head.appendChild(script);
  }

  sendBatch(batch) {
    if (!this.enabled) {
      console.warn('GA4Provider: cannot send batch, not enabled');
      return;
    }

    if (!window.gtag) {
      console.error('❌ GA4Provider: window.gtag is NOT available!');
      console.error('window.gtag type:', typeof window.gtag);
      console.error('window.dataLayer:', window.dataLayer);
      return;
    }

    batch.forEach((event) => {
      try {
        const eventData = {
          ...event.data,
          _timestamp: event.timestamp,
          ...(this.debugMode ? { debug_mode: true } : {}),
        };
        window.gtag('event', event.eventName, eventData);
      } catch (err) {
        console.error('❌ Error sending event to GA4:', err);
      }
    });
  }

  trackPageView(data) {
    if (!this.enabled) {
      console.warn('GA4Provider: not enabled, skipping pageview');
      return;
    }

    this.batcher.add({
      eventName: 'page_view',
      data: {
        page_title: data.title || document.title,
        page_path: data.path || window.location.pathname,
        page_location: data.location || window.location.href,
      },
    });
  }

  trackEvent(eventName, eventData = {}) {
    if (!this.enabled) {
      console.warn('GA4Provider: not enabled, skipping event:', eventName);
      return;
    }

    this.batcher.add({
      eventName,
      data: eventData,
    });
  }

  setUserId(userId) {
    if (!this.enabled || !window.gtag) return;

    window.gtag('config', this.measurementId, {
      user_id: userId,
    });
  }

  setConsentGranted(hasConsent) {
    if (this.consentLocked) {
      console.warn('GA4Provider: Consent decision is locked and cannot be changed');
      return;
    }
    this.hasConsent = hasConsent;
    updateGoogleConsent(hasConsent);

    if (hasConsent && !this.enabled) {
      this.loadGA4Script();
      this.enabled = true;
    }
  }

  _lockConsent() {
    this.consentLocked = true;
  }

  flush() {
    this.batcher.flush();
  }

  destroy() {
    this.batcher.destroy();
  }
}
