/**
 * Line Profiler Parser Utility
 * Parses the markdown table output from Python's line_profiler into structured data
 */

export interface LineProfilerEntry {
  hits: string
  time: string
  perHit: string
  percentTime: number
  lineContents: string
}

export interface LineProfilerFunction {
  functionName: string
  totalTime: string
  entries: LineProfilerEntry[]
}

export interface LineProfilerReport {
  timerUnit: string
  functions: LineProfilerFunction[]
}

/**
 * Parse line profiler results from the markdown table format
 * Expected format:
 * ```
 * # Timer unit: 1e-09 s
 * ## Function: function_name
 * ## Total time: X s
 * | Hits | Time | Per Hit | % Time | Line Contents |
 * |------|------|---------|--------|---------------|
 * | 123  | 456  | 3.7     | 50.0   | def foo():   |
 * ```
 *
 * TODO: Security & Robustness - Add input validation before processing:
 * - Maximum input size limit (e.g., 10MB) to prevent DoS
 * - Maximum line count limit (e.g., 100,000 lines)
 * - Line length validation
 * - Structure validation (expected headers, format)
 *
 * Example:
 * ```typescript
 * if (rawResults.length > 10_000_000) {
 *   throw new Error('Profiler output too large');
 * }
 * const lines = rawResults.split("\n");
 * if (lines.length > 100_000) {
 *   throw new Error('Too many lines in profiler output');
 * }
 * ```
 */
export function parseLineProfilerResults(rawResults: string): LineProfilerReport {
  const report: LineProfilerReport = {
    timerUnit: "",
    functions: [],
  }

  if (!rawResults || rawResults.trim() === "") {
    return report
  }

  // Detect format: JS format starts with "Line Profile Results:" or has space-separated columns
  const isJsFormat =
    rawResults.includes("Line Profile Results:") ||
    (rawResults.includes("Line") && rawResults.includes("Hits") && rawResults.includes("Content") && !rawResults.includes("|"))

  if (isJsFormat) {
    return parseJsLineProfilerResults(rawResults)
  }

  return parsePythonLineProfilerResults(rawResults)
}

/**
 * Parse JS/TS line profiler format:
 * Line Profile Results:
 * File: /path/to/file.js
 * --------------------------------------------------------------------------------
 *   Line      Hits     Time (ms)    % Time  Content
 * --------------------------------------------------------------------------------
 *     12   3442092       397.958    100.0%  if (n <= 1) {
 */
function parseJsLineProfilerResults(rawResults: string): LineProfilerReport {
  const report: LineProfilerReport = {
    timerUnit: "1e-03 s", // JS profiler uses milliseconds
    functions: [],
  }

  const lines = rawResults.split("\n")
  let currentFunction: LineProfilerFunction | null = null
  let inData = false

  for (const line of lines) {
    const trimmedLine = line.trim()

    // Extract file path as function name
    if (trimmedLine.startsWith("File:")) {
      if (currentFunction) {
        report.functions.push(currentFunction)
      }
      const filePath = trimmedLine.replace("File:", "").trim()
      const fileName = filePath.split("/").pop() || filePath
      currentFunction = {
        functionName: fileName,
        totalTime: "",
        entries: [],
      }
      inData = false
      continue
    }

    // Skip header line and separator lines
    if (trimmedLine.startsWith("Line") && trimmedLine.includes("Hits")) {
      inData = false
      continue
    }
    if (trimmedLine.match(/^-+$/)) {
      inData = true
      continue
    }

    // Parse data rows: "    12   3442092       397.958    100.0%  if (n <= 1) {"
    if (inData && currentFunction && trimmedLine.length > 0) {
      // Match: line_number, hits, time, percent, content
      const match = trimmedLine.match(/^\s*(\d+)\s+(\d+)\s+([\d.]+)\s+([\d.]+)%\s+(.*)$/)
      if (match) {
        const [, , hits, time, percent, content] = match
        currentFunction.entries.push({
          hits: hits,
          time: time,
          perHit: hits === "0" ? "0.000" : (parseFloat(time) / parseInt(hits)).toFixed(3),
          percentTime: parseFloat(percent) || 0,
          lineContents: content || " ",
        })
      }
    }
  }

  if (currentFunction) {
    report.functions.push(currentFunction)
  }

  return report
}

/**
 * Parse Python line_profiler markdown table format
 */
function parsePythonLineProfilerResults(rawResults: string): LineProfilerReport {
  const report: LineProfilerReport = {
    timerUnit: "",
    functions: [],
  }

  const lines = rawResults.split("\n")
  let currentFunction: LineProfilerFunction | null = null
  let inTable = false
  let headerPassed = false

  for (const line of lines) {
    const trimmedLine = line.trim()

    // Parse timer unit
    if (trimmedLine.startsWith("# Timer unit:")) {
      report.timerUnit = trimmedLine.replace("# Timer unit:", "").trim()
      continue
    }

    // Parse function name
    if (trimmedLine.startsWith("## Function:")) {
      if (currentFunction) {
        report.functions.push(currentFunction)
      }
      currentFunction = {
        functionName: trimmedLine.replace("## Function:", "").trim(),
        totalTime: "",
        entries: [],
      }
      inTable = false
      headerPassed = false
      continue
    }

    // Parse total time
    if (trimmedLine.startsWith("## Total time:")) {
      if (currentFunction) {
        currentFunction.totalTime = trimmedLine.replace("## Total time:", "").trim()
      }
      continue
    }

    // Detect table header - handle variable whitespace in cells
    // Tabulate may produce "|   Hits |" with extra spaces
    if (trimmedLine.includes("Hits") && trimmedLine.includes("Line Contents") && trimmedLine.startsWith("|")) {
      inTable = true
      headerPassed = false
      continue
    }

    // Skip separator line (|---|---|...) - also handles alignment colons like |-------:|
    if (inTable && trimmedLine.match(/^\|[-\s|:]+\|$/)) {
      headerPassed = true
      continue
    }

    // Parse table rows
    if (inTable && headerPassed && trimmedLine.startsWith("|") && currentFunction) {
      // Split by | but preserve the original line for extracting code with whitespace
      const rawParts = trimmedLine.split("|")
      // Trim stats columns but NOT the code column
      const statParts = rawParts.slice(1, 5).map((p) => p.trim())
      // Keep code with original whitespace - join remaining parts (code may contain pipes)
      // Use " " for empty lines to preserve blank lines in display
      const codePart = rawParts.slice(5, -1).join("|") || " "

      if (statParts.length >= 4) {
        const percentStr = statParts[3] || "0"
        const percentTime = parseFloat(percentStr) || 0

        currentFunction.entries.push({
          hits: statParts[0] || "",
          time: statParts[1] || "",
          perHit: statParts[2] || "",
          percentTime,
          lineContents: codePart, // Preserve whitespace in code
        })
      }
    }
  }

  // Don't forget the last function
  if (currentFunction) {
    report.functions.push(currentFunction)
  }

  return report
}

/**
 * Heat level thresholds for performance visualization (% of total time)
 */
export const HEAT_THRESHOLDS = {
  HOT_4: 50, // >= 50% - Critical hotspot
  HOT_3: 30, // >= 30% - High impact
  HOT_2: 15, // >= 15% - Medium impact
  HOT_1: 5, // >= 5%  - Low impact
} as const

/**
 * Get the heat level for a given percent time
 * Returns a class suffix for CSS styling
 */
export function getHeatLevel(
  percentTime: number,
): "cold" | "hot-1" | "hot-2" | "hot-3" | "hot-4" {
  if (percentTime >= HEAT_THRESHOLDS.HOT_4) return "hot-4"
  if (percentTime >= HEAT_THRESHOLDS.HOT_3) return "hot-3"
  if (percentTime >= HEAT_THRESHOLDS.HOT_2) return "hot-2"
  if (percentTime >= HEAT_THRESHOLDS.HOT_1) return "hot-1"
  return "cold"
}

/**
 * Calculate the maximum percent time across all entries for normalization
 */
export function getMaxPercentTime(report: LineProfilerReport): number {
  let max = 0
  for (const func of report.functions) {
    for (const entry of func.entries) {
      if (entry.percentTime > max) {
        max = entry.percentTime
      }
    }
  }
  return max || 100
}

/**
 * Format timer unit to human-readable string
 * e.g., "1e-09 s" → "1 ns", "1e-06 s" → "1 µs"
 */
export function formatTimerUnit(timerUnit: string): string {
  if (!timerUnit || timerUnit.trim() === "") return ""

  const unitMatch = timerUnit.match(/([0-9.e+-]+)\s*s/)
  if (!unitMatch) return timerUnit

  const scaleFactor = parseFloat(unitMatch[1])

  if (scaleFactor >= 1) {
    return `${scaleFactor} s`
  } else if (scaleFactor >= 1e-3) {
    return `${scaleFactor * 1000} ms`
  } else if (scaleFactor >= 1e-6) {
    return `${scaleFactor * 1e6} µs`
  } else if (scaleFactor >= 1e-9) {
    return `${scaleFactor * 1e9} ns`
  } else {
    return `${scaleFactor * 1e12} ps`
  }
}

/**
 * Format time value to human-readable string
 */
export function formatTime(timeStr: string, timerUnit: string): string {
  if (!timeStr || timeStr === "") return ""

  // Parse the timer unit to get the scale factor
  // Common units: "1e-09 s" (nanoseconds), "1e-06 s" (microseconds), etc.
  let scaleFactor = 1e-9 // Default to nanoseconds
  const unitMatch = timerUnit.match(/([0-9.e+-]+)\s*s/)
  if (unitMatch) {
    scaleFactor = parseFloat(unitMatch[1])
  }

  // Parse the time value
  const timeValue = parseFloat(timeStr.replace(/,/g, ""))
  if (isNaN(timeValue)) return timeStr

  // Convert to seconds
  const seconds = timeValue * scaleFactor

  // Format based on magnitude
  if (seconds >= 3600) {
    return `${(seconds / 3600).toFixed(2)}h`
  } else if (seconds >= 60) {
    return `${(seconds / 60).toFixed(2)}m`
  } else if (seconds >= 1) {
    return `${seconds.toFixed(2)}s`
  } else if (seconds >= 0.001) {
    return `${(seconds * 1000).toFixed(2)}ms`
  } else if (seconds >= 0.000001) {
    return `${(seconds * 1000000).toFixed(2)}µs`
  } else {
    return `${(seconds * 1000000000).toFixed(2)}ns`
  }
}
