/**
 * HAR Parser - Extract network request data from Lighthouse results
 * Provides timing, size, and metadata for waterfall visualization
 */

/**
 * Parse Lighthouse result and generate HAR-compatible data
 * @param {object} lighthouseResult - Full Lighthouse result object
 * @returns {object} HAR data structure
 */
function parseHAR(lighthouseResult) {
  const audits = lighthouseResult.audits;
  const networkRequests = audits['network-requests']?.details?.items || [];
  
  const entries = networkRequests.map((request, index) => {
    const timing = calculateTiming(request);
    
    return {
      requestId: index + 1,
      url: request.url,
      method: request.requestMethod || 'GET',
      status: request.statusCode,
      mimeType: request.mimeType || request.resourceType,
      resourceType: request.resourceType,
      protocol: request.protocol,
      priority: request.priority,
      
      // Timing breakdown (in milliseconds)
      timing: {
        dns: timing.dns,
        connect: timing.connect,
        ssl: timing.ssl,
        send: timing.send,
        wait: timing.wait,
        receive: timing.receive,
        total: timing.total,
        startTime: request.startTime,
        endTime: request.endTime
      },
      
      // Size information (in bytes)
      size: {
        transferSize: request.transferSize || 0,
        resourceSize: request.resourceSize || 0,
        compressionRatio: request.resourceSize > 0 
          ? (request.transferSize / request.resourceSize).toFixed(2)
          : 1
      },
      
      // Additional metadata
      isSecure: request.url?.startsWith('https://'),
      domain: extractDomain(request.url),
      isThirdParty: checkIfThirdParty(request.url, lighthouseResult.finalUrl),
      renderBlocking: request.renderBlocking === 'blocking',
      
      // HTTP Headers
      requestHeaders: request.requestHeaders || {},
      responseHeaders: request.responseHeaders || {},
      
      // Extracted from response headers if available
      cacheControl: request.responseHeaders?.['cache-control'],
      contentEncoding: request.responseHeaders?.['content-encoding']
    };
  });
  
  return {
    entries,
    summary: calculateSummary(entries),
    pageMetrics: extractPageMetrics(lighthouseResult)
  };
}

/**
 * Calculate timing breakdown for a single request
 */
function calculateTiming(request) {
  const start = request.startTime || 0;
  const end = request.endTime || start;
  const total = (end - start) * 1000; // Convert to ms
  
  // Parse timing object if available
  const timing = request.timing || {};
  
  return {
    dns: timing.dnsEnd >= 0 ? (timing.dnsEnd - timing.dnsStart) : -1,
    connect: timing.connectEnd >= 0 ? (timing.connectEnd - timing.connectStart) : -1,
    ssl: timing.sslEnd >= 0 ? (timing.sslEnd - timing.sslStart) : -1,
    send: timing.sendEnd >= 0 ? (timing.sendEnd - timing.sendStart) : -1,
    wait: timing.receiveHeadersEnd >= 0 ? (timing.receiveHeadersEnd - timing.sendEnd) : -1,
    receive: -1, // Calculated from total - (dns + connect + ssl + send + wait)
    total: total > 0 ? total : (request.networkEndTime - request.networkRequestTime) * 1000 || 0,
    startTime: start,
    endTime: end
  };
}

/**
 * Calculate summary statistics
 */
function calculateSummary(entries) {
  const byType = {};
  let totalSize = 0;
  let totalTransfer = 0;
  
  entries.forEach(entry => {
    const type = entry.resourceType || 'Other';
    
    if (!byType[type]) {
      byType[type] = { count: 0, size: 0, transfer: 0 };
    }
    
    byType[type].count++;
    byType[type].size += entry.size.resourceSize;
    byType[type].transfer += entry.size.transferSize;
    
    totalSize += entry.size.resourceSize;
    totalTransfer += entry.size.transferSize;
  });
  
  return {
    totalRequests: entries.length,
    totalSize,
    totalTransfer,
    byType,
    compressionSavings: totalSize > 0 ? ((totalSize - totalTransfer) / totalSize * 100).toFixed(1) : 0
  };
}

/**
 * Extract key page metrics from Lighthouse
 */
function extractPageMetrics(lighthouseResult) {
  const audits = lighthouseResult.audits;
  
  return {
    firstContentfulPaint: audits['first-contentful-paint']?.numericValue,
    largestContentfulPaint: audits['largest-contentful-paint']?.numericValue,
    cumulativeLayoutShift: audits['cumulative-layout-shift']?.numericValue,
    totalBlockingTime: audits['total-blocking-time']?.numericValue,
    speedIndex: audits['speed-index']?.numericValue,
    timeToInteractive: audits['interactive']?.numericValue,
    domContentLoaded: lighthouseResult.audits['metrics']?.details?.items?.[0]?.observedDomContentLoaded,
    loadEventEnd: lighthouseResult.audits['metrics']?.details?.items?.[0]?.observedLoad
  };
}

/**
 * Extract domain from URL
 */
function extractDomain(url) {
  try {
    const urlObj = new URL(url);
    return urlObj.hostname;
  } catch {
    return 'unknown';
  }
}

/**
 * Check if request is third-party
 */
function checkIfThirdParty(requestUrl, pageUrl) {
  const requestDomain = extractDomain(requestUrl);
  const pageDomain = extractDomain(pageUrl);
  return requestDomain !== pageDomain;
}

/**
 * Group entries by domain
 */
function groupByDomain(entries) {
  const domains = {};
  
  entries.forEach(entry => {
    const domain = entry.domain;
    if (!domains[domain]) {
      domains[domain] = {
        count: 0,
        size: 0,
        transfer: 0,
        requests: []
      };
    }
    
    domains[domain].count++;
    domains[domain].size += entry.size.resourceSize;
    domains[domain].transfer += entry.size.transferSize;
    domains[domain].requests.push(entry.requestId);
  });
  
  // Sort by transfer size (descending)
  return Object.entries(domains)
    .sort((a, b) => b[1].transfer - a[1].transfer)
    .reduce((acc, [domain, data]) => {
      acc[domain] = data;
      return acc;
    }, {});
}

module.exports = {
  parseHAR,
  calculateTiming,
  calculateSummary,
  groupByDomain
};
