import { Platform } from 'react-native';
import { MMKV } from 'react-native-mmkv';
import * as FileSystem from 'expo-file-system/legacy';
import * as MapLibreRN from '@maplibre/maplibre-react-native';

const telemetryStorage = new MMKV({ id: 'telemetry_storage_v1' });
const EVENTS_KEY = 'events';

export const APP_OPEN_TIME = Date.now();

export interface TelemetryEvent {
  id: string;
  type: 'api_request' | 'file_download' | 'map_tile_pack' | 'other';
  timestamp: number;
  url: string;
  method?: string;
  caller: string;
  reqSize: number;
  resSize: number;
  status: number;
  duration: number;
}

export function sanitizeUrlForDisplay(url: string): string {
  if (!url) return '';
  let clean = url.split('?')[0];
  
  clean = clean.split('/').map(segment => {
    if (segment && !isNaN(Number(segment))) {
      return ':id';
    }

    const dotIndex = segment.lastIndexOf('.');
    if (dotIndex !== -1) {
      const name = segment.substring(0, dotIndex);
      const ext = segment.substring(dotIndex);
      
      const cleanName = name
        .replace('_visited', '')
        .replace('visited', '')
        .replace('v', '');
        
      const isNumeric = cleanName !== '' && !isNaN(Number(cleanName));
      if (isNumeric) {
        const isVisited = name.includes('_visited') || name.includes('visited') || name.endsWith('v');
        return isVisited ? `:id_visited${ext}` : `:id${ext}`;
      }
    }
    return segment;
  }).join('/');
  
  return clean;
}

export function inferCallerFromUrl(url: string): string {
  if (!url) return 'Other';
  
  const lowerUrl = url.toLowerCase();
  
  if (lowerUrl.includes('.db')) {
    return 'Databases (.db)';
  }
  if (lowerUrl.includes('/flags/') || lowerUrl.includes('/flags_new/')) {
    return 'Flags';
  }
  if (lowerUrl.includes('/series_new2_small/')) {
    return 'Series Icons';
  }
  if (lowerUrl.includes('map-pack://') || lowerUrl.includes('offline-map')) {
    return 'Offline Maps';
  }
  if (lowerUrl.endsWith('.png') || lowerUrl.endsWith('.jpg') || lowerUrl.endsWith('.jpeg') || lowerUrl.endsWith('.svg') || lowerUrl.endsWith('.gif') || lowerUrl.endsWith('.webp')) {
    return 'Downloads';
  }
  
  try {
    const cleanUrl = url.split('?')[0];
    const parts = cleanUrl.split('/');
    
    const apiIndex = parts.findIndex(p => p.toLowerCase() === 'api');
    if (apiIndex !== -1 && apiIndex + 1 < parts.length) {
      const moduleName = parts[apiIndex + 1].toLowerCase();
      return moduleName.charAt(0) + moduleName.slice(1);
    }
    
    const cleanParts = parts.filter(p => p && !p.includes(':') && !p.includes('.'));
    if (cleanParts.length > 0) {
      const moduleName = cleanParts[0].toLowerCase();
      return moduleName.charAt(0) + moduleName.slice(1);
    }
  } catch {}

  return 'Other';
}

export function getTelemetryEvents(): TelemetryEvent[] {
  try {
    const data = telemetryStorage.getString(EVENTS_KEY);
    return data ? JSON.parse(data) : [];
  } catch (error) {
    console.error('Failed to parse telemetry events:', error);
    return [];
  }
}

export function addTelemetryEvent(event: Omit<TelemetryEvent, 'timestamp' | 'id'>) {
  try {
    const events = getTelemetryEvents();
    
    const ONE_WEEK_MS = 7 * 24 * 60 * 60 * 1000;
    const cutoff = Date.now() - ONE_WEEK_MS;
    let cleanEvents = events.filter(e => e.timestamp >= cutoff);

    const latest = cleanEvents[0];
    if (latest && latest.url === event.url && (event.type === 'map_tile_pack' || event.type === 'file_download')) {
      latest.resSize += event.resSize;
      latest.reqSize += event.reqSize;
      latest.duration += event.duration;
      latest.timestamp = Date.now();
    } else {
      const newEvent: TelemetryEvent = {
        ...event,
        id: `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`,
        timestamp: Date.now()
      };
      cleanEvents.unshift(newEvent);
    }
    
    telemetryStorage.set(EVENTS_KEY, JSON.stringify(cleanEvents));
  } catch (error) {
    console.error('Failed to save telemetry event:', error);
  }
}

export function clearTelemetryEvents() {
  try {
    telemetryStorage.delete(EVENTS_KEY);
  } catch (error) {
    console.error('Failed to clear telemetry events:', error);
  }
}

export async function getAmbientCacheSize(): Promise<number> {
  try {
    const packs = await MapLibreRN.OfflineManager.getPacks();
    let totalSize = 0;
    for (const pack of packs) {
      try {
        const status = await pack.status();
        if (status) {
          totalSize += status.completedResourceSize || 0;
        }
      } catch {}
    }
    return totalSize;
  } catch (error) {
    console.warn('Failed to get MapLibre offline packs size:', error);
    return 0;
  }
}

export function getTelemetrySummary() {
  const events = getTelemetryEvents();
  let totalDownloaded = 0;
  let totalUploaded = 0;
  const callerBreakdown: Record<string, { count: number; downloaded: number; duration: number }> = {};
  const typeBreakdown: Record<string, { count: number; downloaded: number }> = {};

  for (const event of events) {
    totalDownloaded += event.resSize;
    totalUploaded += event.reqSize;

    const caller = event.caller || 'Other';
    if (!callerBreakdown[caller]) {
      callerBreakdown[caller] = { count: 0, downloaded: 0, duration: 0 };
    }
    callerBreakdown[caller].count += 1;
    callerBreakdown[caller].downloaded += event.resSize;
    callerBreakdown[caller].duration += event.duration;

    const type = event.type;
    if (!typeBreakdown[type]) {
      typeBreakdown[type] = { count: 0, downloaded: 0 };
    }
    typeBreakdown[type].count += 1;
    typeBreakdown[type].downloaded += event.resSize;
  }

  return {
    totalEvents: events.length,
    totalDownloaded,
    totalUploaded,
    callerBreakdown: Object.entries(callerBreakdown)
      .map(([name, data]) => ({
        name,
        count: data.count,
        downloaded: data.downloaded,
        avgDuration: data.count > 0 ? Math.round(data.duration / data.count) : 0
      }))
      .sort((a, b) => b.downloaded - a.downloaded),
    typeBreakdown: Object.entries(typeBreakdown)
      .map(([name, data]) => ({
        name,
        count: data.count,
        downloaded: data.downloaded
      }))
      .sort((a, b) => b.downloaded - a.downloaded)
  };
}

export function attachTelemetryInterceptors(axiosInstance: any) {
  axiosInstance.interceptors.request.use(
    (config: any) => {
      try {
        config.metadata = { startTime: Date.now() };
      } catch {}
      return config;
    },
    (error: any) => {
      return Promise.reject(error);
    }
  );

  axiosInstance.interceptors.response.use(
    (response: any) => {
      try {
        const startTime = response.config?.metadata?.startTime || Date.now();
        const duration = Date.now() - startTime;
        
        let reqSize = 0;
        if (response.config?.data) {
          try {
            reqSize = typeof response.config.data === 'string' 
              ? response.config.data.length 
              : JSON.stringify(response.config.data).length;
          } catch {}
        }
        
        let resSize = 0;
        if (response.data) {
          try {
            resSize = typeof response.data === 'string'
              ? response.data.length
              : JSON.stringify(response.data).length;
          } catch {}
        }

        const url = response.config?.url || '';
        const method = response.config?.method?.toUpperCase() || 'GET';
        const caller = inferCallerFromUrl(url);

        addTelemetryEvent({
          type: 'api_request',
          url,
          method,
          caller,
          reqSize,
          resSize,
          status: response.status || 200,
          duration
        });
      } catch (error) {
        console.error('Failed to log response telemetry:', error);
      }
      return response;
    },
    (error: any) => {
      try {
        const startTime = error.config?.metadata?.startTime || Date.now();
        const duration = Date.now() - startTime;

        let reqSize = 0;
        if (error.config?.data) {
          try {
            reqSize = typeof error.config.data === 'string'
              ? error.config.data.length
              : JSON.stringify(error.config.data).length;
          } catch {}
        }

        const url = error.config?.url || '';
        const method = error.config?.method?.toUpperCase() || 'GET';
        const caller = inferCallerFromUrl(url);

        addTelemetryEvent({
          type: 'api_request',
          url,
          method,
          caller,
          reqSize,
          resSize: 0,
          status: error.response?.status || 0,
          duration
        });
      } catch {}
      return Promise.reject(error);
    }
  );
}
