import type { HTTPRequest } from '../types/httpRequest'

export interface CSVExportOptions {
  includeHeaders?: boolean
  selectedColumns?: string[]
}

const DEFAULT_COLUMNS = [
  'method',
  'url',
  'hostname',
  'statusCode',
  'resourceType',
  'priority',
  'protocol',
  'connectionNumber',
  'requestNumberOnConnection',
  'timing.start',
  'timing.queueTime',
  'dnsTime',
  'connectionTime',
  'timing.serverLatency',
  'timing.duration',
  'timing.totalResponseTime',
  'dataRate',
  'size',
  'contentLength',
  'fromCache',
  'connectionReused',
  'cdnAnalysis.provider',
  'queueAnalysis.reason'
]

// Format a value for CSV output
const formatCSVValue = (value: any): string => {
  if (value === null || value === undefined) {
    return ''
  }
  
  if (typeof value === 'number') {
    return value.toString()
  }
  
  if (typeof value === 'boolean') {
    return value ? 'true' : 'false'
  }
  
  const stringValue = value.toString()
  
  // Escape quotes and wrap in quotes if contains comma, quote, or newline
  if (stringValue.includes(',') || stringValue.includes('"') || stringValue.includes('\n')) {
    return `"${stringValue.replace(/"/g, '""')}"`
  }
  
  return stringValue
}

// Calculate derived values for CSV export
const calculateDerivedValue = (request: HTTPRequest, path: string): any => {
  switch (path) {
    case 'dnsTime':
      if (request.timing.dnsStart !== undefined && request.timing.dnsEnd !== undefined && 
          request.timing.dnsStart >= 0 && request.timing.dnsEnd >= 0) {
        return request.timing.dnsEnd - request.timing.dnsStart
      }
      return null
    case 'connectionTime':
      if (request.timing.connectStart !== undefined && request.timing.connectEnd !== undefined && 
          request.timing.connectStart >= 0 && request.timing.connectEnd >= 0) {
        return request.timing.connectEnd - request.timing.connectStart
      }
      return null
    case 'dataRate':
      if (!request.timing.duration || request.timing.duration <= 0) return null
      const bytes = request.contentLength && request.contentLength > 0 ? request.contentLength : request.encodedDataLength
      if (!bytes) return null
      const durationSeconds = request.timing.duration / 1000000
      return bytes / durationSeconds // bytes per second
    case 'size':
      return request.encodedDataLength || request.contentLength || null
    default:
      return getNestedValue(request, path)
  }
}

// Get nested property value from object
const getNestedValue = (obj: any, path: string): any => {
  return path.split('.').reduce((current, key) => {
    return current && current[key] !== undefined ? current[key] : null
  }, obj)
}

// Convert HTTP requests to CSV format
export const exportRequestsToCSV = (
  requests: HTTPRequest[], 
  options: CSVExportOptions = {}
): string => {
  const { 
    includeHeaders = true, 
    selectedColumns = DEFAULT_COLUMNS 
  } = options
  
  if (requests.length === 0) {
    return includeHeaders ? selectedColumns.join(',') + '\n' : ''
  }
  
  const lines: string[] = []
  
  // Add headers if requested
  if (includeHeaders) {
    const headers = selectedColumns.map(col => {
      // Add units to timing-related headers
      switch (col) {
        case 'timing.start':
          return 'Start Time (μs)'
        case 'timing.queueTime':
          return 'Queue Time (μs)'
        case 'dnsTime':
          return 'DNS Time (μs)'
        case 'connectionTime':
          return 'Connection Time (μs)'
        case 'timing.serverLatency':
          return 'Server Latency (μs)'
        case 'timing.duration':
          return 'Duration (μs)'
        case 'timing.totalResponseTime':
          return 'Total Response Time (μs)'
        case 'timing.downloadTime':
          return 'Download Time (μs)'
        case 'dataRate':
          return 'Data Rate (bytes/sec)'
        case 'size':
          return 'Size (bytes)'
        case 'contentLength':
          return 'Content Length (bytes)'
        case 'encodedDataLength':
          return 'Encoded Data Length (bytes)'
        default:
          // Clean up column names for other headers
          return col
            .replace(/([A-Z])/g, ' $1') // Add space before capitals
            .replace(/^\w/, c => c.toUpperCase()) // Capitalize first letter
            .replace(/\./g, ' ') // Replace dots with spaces
            .trim()
      }
    })
    lines.push(headers.map(formatCSVValue).join(','))
  }
  
  // Add data rows
  for (const request of requests) {
    const values = selectedColumns.map(column => {
      const value = calculateDerivedValue(request, column)
      return formatCSVValue(value)
    })
    lines.push(values.join(','))
  }
  
  return lines.join('\n')
}

// Download CSV file
export const downloadCSV = (csvContent: string, filename: string = 'http-requests.csv'): void => {
  const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })
  const link = document.createElement('a')
  
  if (link.download !== undefined) {
    // Use HTML5 download attribute
    const url = URL.createObjectURL(blob)
    link.setAttribute('href', url)
    link.setAttribute('download', filename)
    link.style.visibility = 'hidden'
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    URL.revokeObjectURL(url)
  }
}

// Get all available columns from HTTP requests
export const getAvailableColumns = (requests: HTTPRequest[]): string[] => {
  if (requests.length === 0) {
    return DEFAULT_COLUMNS
  }
  
  const columns = new Set<string>()
  
  const extractColumns = (obj: any, prefix = ''): void => {
    Object.keys(obj).forEach(key => {
      const fullKey = prefix ? `${prefix}.${key}` : key
      const value = obj[key]
      
      if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
        // Recursively extract nested properties
        extractColumns(value, fullKey)
      } else {
        columns.add(fullKey)
      }
    })
  }
  
  // Extract columns from first request
  extractColumns(requests[0])
  
  return Array.from(columns).sort()
}