import { trace } from '@opentelemetry/api';
import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';

// Types and Interfaces
interface AnalyticsMetadata {
  [key: string]: string | number | boolean | undefined;
}

// Constants
const ANALYTICS_ENABLED_KEY = 'analyticsEnabled';
const LOCATION_CONSENT_KEY = 'locationTrackingConsent';
const SESSION_ID_KEY = 'sessionId';
const USER_ID_KEY = 'userId';

// Generate a unique session ID
const generateSessionId = (): string => {
  return Date.now().toString(36) + Math.random().toString(36).substring(2);
};

// Get current user ID (implement based on your auth system)
export const getCurrentUserId = (): string | null => {
  // This is a placeholder - implement based on your authentication system
  // For example, you might get this from localStorage, cookies, or context
  return localStorage.getItem(USER_ID_KEY) || sessionStorage.getItem(USER_ID_KEY) || null;
};

// Track page view
export const trackPageView = (pathname: string): void => {
  // Check if analytics are enabled
  if (!isAnalyticsEnabled()) {
    return;
  }

  try {
    const tracer = trace.getTracer('bakery-frontend');
    const user_id = getCurrentUserId();

    const span = tracer.startSpan('page_view', {
      attributes: {
        [ATTR_HTTP_ROUTE]: pathname,
        'user.id': user_id || 'anonymous',
        'page.path': pathname,
      }
    });

    // End the span immediately for page views
    span.end();
  } catch (error) {
    console.error('Failed to track page view:', error);
  }
};

// Check if analytics are enabled
export const isAnalyticsEnabled = (): boolean => {
  return localStorage.getItem(ANALYTICS_ENABLED_KEY) !== 'false';
};

// Enable or disable analytics
export const setAnalyticsEnabled = (enabled: boolean): void => {
  localStorage.setItem(ANALYTICS_ENABLED_KEY, enabled.toString());
};

// Check if location tracking consent is granted
export const isLocationTrackingConsentGranted = (): boolean => {
  return localStorage.getItem(LOCATION_CONSENT_KEY) === 'granted';
};

// Set location tracking consent
export const setLocationTrackingConsent = (granted: boolean): void => {
  localStorage.setItem(LOCATION_CONSENT_KEY, granted ? 'granted' : 'denied');
};

// Track user session
export const trackSession = (): (() => void) => {
  // Check if analytics are enabled
  if (!isAnalyticsEnabled()) {
    console.log('Analytics disabled by user preference');
    return () => {}; // Return no-op cleanup function
  }

  try {
    const tracer = trace.getTracer('bakery-frontend');
    const sessionId = generateSessionId();
    const userId = getCurrentUserId();

    const span = tracer.startSpan('user_session', {
      attributes: {
        'session.id': sessionId,
        'user.id': userId || 'anonymous',
        'browser.user_agent': navigator.userAgent,
        'screen.width': window.screen.width.toString(),
        'screen.height': window.screen.height.toString(),
        'device.type': /mobile|tablet|ipad|iphone|ipod|android|silk/i.test(navigator.userAgent) ? 'mobile' : 'desktop'
      }
    });

    // Store session ID in sessionStorage for later use
    sessionStorage.setItem(SESSION_ID_KEY, sessionId);

    // End span when session ends
    const handleBeforeUnload = () => {
      span.end();
    };
    
    window.addEventListener('beforeunload', handleBeforeUnload);
    
    // Clean up event listener when needed
    return () => {
      window.removeEventListener('beforeunload', handleBeforeUnload);
    };
  } catch (error) {
    console.error('Failed to track session:', error);
    return () => {}; // Return no-op cleanup function
  }
};

// Track user action
export const trackUserAction = (action: string, metadata?: AnalyticsMetadata): void => {
  // Check if analytics are enabled
  if (!isAnalyticsEnabled()) {
    return;
  }

  try {
    const tracer = trace.getTracer('bakery-frontend');
    const userId = getCurrentUserId();

    const span = tracer.startSpan('user_action', {
      attributes: {
        'user.action': action,
        'user.id': userId || 'anonymous',
        ...metadata
      }
    });

    span.end();
  } catch (error) {
    console.error('Failed to track user action:', error);
  }
};

// Track user location (with consent)
export const trackUserLocation = async (): Promise<void> => {
  // Check if analytics are enabled
  if (!isAnalyticsEnabled()) {
    return;
  }

  // Check if location tracking consent is granted
  if (!isLocationTrackingConsentGranted()) {
    console.log('Location tracking consent not granted');
    return;
  }

  try {
    const position = await new Promise<GeolocationPosition>((resolve, reject) => {
      if (!navigator.geolocation) {
        reject(new Error('Geolocation not supported'));
        return;
      }
      
      navigator.geolocation.getCurrentPosition(resolve, reject, {
        enableHighAccuracy: false,
        timeout: 10000,
        maximumAge: 300000 // 5 minutes
      });
    });

    const tracer = trace.getTracer('bakery-frontend');
    const userId = getCurrentUserId();

    const span = tracer.startSpan('user_location', {
      attributes: {
        'user.id': userId || 'anonymous',
        'location.latitude': position.coords.latitude,
        'location.longitude': position.coords.longitude,
        'location.accuracy': position.coords.accuracy,
        'location.altitude': position.coords.altitude ?? undefined,
        'location.speed': position.coords.speed ?? undefined,
        'location.heading': position.coords.heading ?? undefined
      }
    });

    span.end();
  } catch (error) {
    console.log('Location access denied or unavailable:', error);
  }
};

// Initialize analytics tracking
export const initializeAnalytics = (): (() => void) => {
  // Track initial session
  const cleanupSession = trackSession();

  // Track initial page view
  trackPageView(window.location.pathname);

  // Listen for route changes (for SPA navigation)
  let previousUrl = window.location.href;
  
  // For hash-based routing
  const handleHashChange = () => {
    if (window.location.href !== previousUrl) {
      trackPageView(window.location.pathname + window.location.search);
      previousUrl = window.location.href;
    }
  };

  // For history API-based routing (most common in React apps)
  // Use proper typing for history state methods
  const originalPushState = history.pushState.bind(history);
  const handlePushState = function (
    this: History,
    data: unknown,
    unused: string,
    url?: string | URL | null
  ) {
    originalPushState(data, unused, url);
    setTimeout(() => {
      if (window.location.href !== previousUrl) {
        trackPageView(window.location.pathname + window.location.search);
        previousUrl = window.location.href;
      }
    }, 0);
  };

  const originalReplaceState = history.replaceState.bind(history);
  const handleReplaceState = function (
    this: History,
    data: unknown,
    unused: string,
    url?: string | URL | null
  ) {
    originalReplaceState(data, unused, url);
    setTimeout(() => {
      if (window.location.href !== previousUrl) {
        trackPageView(window.location.pathname + window.location.search);
        previousUrl = window.location.href;
      }
    }, 0);
  };

  // Override history methods
  history.pushState = handlePushState;
  history.replaceState = handleReplaceState;

  // Add event listeners
  window.addEventListener('hashchange', handleHashChange);

  // Track user consent for location if needed
  if (isLocationTrackingConsentGranted()) {
    trackUserLocation();
  }

  // Return cleanup function
  return () => {
    // Restore original history methods
    history.pushState = originalPushState;
    history.replaceState = originalReplaceState;
    
    // Remove event listeners
    window.removeEventListener('hashchange', handleHashChange);
    
    // Clean up session tracking
    cleanupSession();
  };
};

// Function to track custom metrics using OpenTelemetry spans
export const trackCustomMetric = (
  name: string,
  value: number,
  attributes?: Record<string, string>
): void => {
  // Check if analytics are enabled
  if (!isAnalyticsEnabled()) {
    return;
  }

  try {
    // Record metric as a span with the value as an attribute
    // This approach works well for browser-based metrics since
    // the OpenTelemetry metrics API in browsers sends to the same collector
    const tracer = trace.getTracer('bakery-frontend');
    const userId = getCurrentUserId();

    const span = tracer.startSpan('custom_metric', {
      attributes: {
        'metric.name': name,
        'metric.value': value,
        'user.id': userId || 'anonymous',
        ...attributes
      }
    });

    span.end();
  } catch (error) {
    // Log error but don't fail - metrics are non-critical
    console.warn('Failed to track custom metric:', error);
  }
};