import fs from "node:fs"
import path, { dirname } from "node:path"
import { fileURLToPath } from "node:url"
import { PrCommentFields } from "./create-pr-from-diffcontents.js"
import { OptimizationReview } from "../OptimizationReview.js"

export function generateOptimizationReviewTemplate(optimizationReview: string): string {
  // Return empty string if optimizationReview is empty
  if (!optimizationReview || optimizationReview === "") {
    return ""
  }

  // Determine review rating level and color based on optimizationReview parameter
  let review_rating: string
  let color: string

  switch (optimizationReview.toLowerCase()) {
    case "high":
      review_rating = "high"
      color = "green"
      break
    case "medium":
      review_rating = "medium"
      color = "blue"
      break
    case "low":
      review_rating = "low"
      color = "yellow"
      break
    default:
      // Default to low if unrecognized value
      review_rating = "low"
      color = "yellow"
  }

  // Generate the badge link with appropriate impact and color
  const badgeUrl = `https://img.shields.io/badge/🎯_Optimization_Quality-${review_rating}-${color}`

  return `![Static Badge](${badgeUrl})\n`
}

// Helper function to create invisible HTML metadata
export function buildOptimizationMetadata(fields: PrCommentFields, trace_id: string): string {
  const metadata: {
    trace_id: string
    function: string
    file: string
    speedup_pct: string
    speedup_x: string
    original_runtime: string
    best_runtime: string
    optimization_type: string
    timestamp: string
    version: string
    original_async_throughput?: string
    best_async_throughput?: string
  } = {
    trace_id,
    function: fields.function_name,
    file: fields.file_path,
    speedup_pct: fields.speedup_pct,
    speedup_x: fields.speedup_x,
    original_runtime: fields.original_runtime,
    best_runtime: fields.best_runtime,
    optimization_type: fields.optimization_explanation
      ? fields.optimization_explanation.toLowerCase().includes("loop")
        ? "loop"
        : fields.optimization_explanation.toLowerCase().includes("memory")
          ? "memory"
          : fields.optimization_explanation.toLowerCase().includes("algorithm")
            ? "algorithm"
            : "general"
      : "general",
    timestamp: new Date().toISOString(),
    version: "1.0",
  }

  // Include throughput data for async functions
  if (fields.original_async_throughput && fields.best_async_throughput) {
    metadata.original_async_throughput = fields.original_async_throughput
    metadata.best_async_throughput = fields.best_async_throughput
  }

  return `<!-- CODEFLASH_OPTIMIZATION: ${JSON.stringify(metadata)} -->`
}

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

// moving it to lazy load the files
let _PR_HEADER_TEMPLATE: string | undefined
let _PR_REVIEW_HEADER_TEMPLATE: string | undefined
let _PR_DETAILS_TEMPLATE: string | undefined
let _PR_DETAILS_TEMPLATE_COLLAPSED: string | undefined
let _PR_TEST_REPORT_TEMPLATE: string | undefined
let _PR_BENCHMARK_INFO_TEMPLATE: string | undefined

const getPrHeaderTemplate = (): string => {
  if (_PR_HEADER_TEMPLATE === undefined) {
    _PR_HEADER_TEMPLATE = fs.readFileSync(
      path.join(__dirname, "optimization_results_header.md"),
      "utf8",
    )
  }
  return _PR_HEADER_TEMPLATE
}

const getPrReviewHeaderTemplate = (): string => {
  if (_PR_REVIEW_HEADER_TEMPLATE === undefined) {
    _PR_REVIEW_HEADER_TEMPLATE = fs.readFileSync(
      path.join(__dirname, "optimization_results_review_header.md"),
      "utf8",
    )
  }
  return _PR_REVIEW_HEADER_TEMPLATE
}

const getPrDetailsTemplate = (): string => {
  if (_PR_DETAILS_TEMPLATE === undefined) {
    _PR_DETAILS_TEMPLATE = fs.readFileSync(
      path.join(__dirname, "optimization_results_details.md"),
      "utf8",
    )
  }
  return _PR_DETAILS_TEMPLATE
}

const getPrDetailsTemplateCollapsed = (): string => {
  if (_PR_DETAILS_TEMPLATE_COLLAPSED === undefined) {
    _PR_DETAILS_TEMPLATE_COLLAPSED = fs.readFileSync(
      path.join(__dirname, "optimization_results_details_collapsed.md"),
      "utf8",
    )
  }
  return _PR_DETAILS_TEMPLATE_COLLAPSED
}

const getPrTestReportTemplate = (): string => {
  if (_PR_TEST_REPORT_TEMPLATE === undefined) {
    _PR_TEST_REPORT_TEMPLATE = fs.readFileSync(
      path.join(__dirname, "optimization_results_test_report.md"),
      "utf8",
    )
  }
  return _PR_TEST_REPORT_TEMPLATE
}

const getPrBenchmarkInfoTemplate = (): string => {
  if (_PR_BENCHMARK_INFO_TEMPLATE === undefined) {
    _PR_BENCHMARK_INFO_TEMPLATE = fs.readFileSync(
      path.join(__dirname, "optimization_results_benchmark_info.md"),
      "utf8",
    )
  }
  return _PR_BENCHMARK_INFO_TEMPLATE
}

const summaryLinesRegex = new RegExp(
  /####\s*(?:📄|⚡️Codeflash found)?\s*([\d,]+(?:\.\d+)?)%\s*\(([\d,.]+)x\)\s*speedup for\s*[*_]*`([^`]+)`[*_]*(?:\s*in\s*`([^`]+)`)?/g,
)

type ReportTable = Record<
  string,
  {
    passed: number
    failed: number
  }
>

export function buildPrCommentBody(
  prCommentFields: PrCommentFields,
  existingTests: any,
  generatedTests: any,
  coverage_message: string,
  newBranchName: string,
  replayTests: any,
  concolicTests: any,
  trace_id: string,
  options: {
    isUnifiedReview?: boolean
    includeHeader?: boolean
    isCollapsed?: boolean
  } = { isUnifiedReview: false, includeHeader: true, isCollapsed: false },
): string {
  const { isUnifiedReview, includeHeader, isCollapsed } = options
  // Build benchmark info if available
  const benchmarkInfo =
    prCommentFields.benchmark_details && prCommentFields.benchmark_details.length > 0
      ? buildBenchmarkInfo(prCommentFields)
      : ""
  return (
    `${buildOptimizationMetadata(prCommentFields, trace_id)}\n${
      includeHeader ? `#### ⚡️ Codeflash found optimizations for this PR\n` : ""
    }${buildResultHeader(prCommentFields, isUnifiedReview)}\n${
      benchmarkInfo ? `${benchmarkInfo}\n` : ""
    }${buildResultDetails(prCommentFields, isCollapsed)}\n` +
    `${buildResultTestReport(
      prCommentFields,
      existingTests,
      generatedTests,
      coverage_message,
      replayTests,
      concolicTests,
    )}\n` +
    `${buildMergeBranchMsg(newBranchName)}\n`
  )
}

export function buildMergeBranchMsg(newBranchName: string): string {
  if (newBranchName?.length > 0) {
    return `To test or edit this optimization locally ` + `\`git merge ${newBranchName}\`\n\n`
  }
  return ""
}

export function buildBenchmarkInfo(fields: PrCommentFields): string {
  if (!fields.benchmark_details || fields.benchmark_details.length === 0) {
    return ""
  }

  // Separate benchmarks into improved and degraded categories
  const improvedBenchmarks = fields.benchmark_details.filter(detail => detail.speedup_percent > 0)
  const degradedBenchmarks = fields.benchmark_details.filter(detail => detail.speedup_percent <= 0)

  // Build improved benchmarks table if there are any
  let improvedBenchmarkInfo = ""
  if (improvedBenchmarks.length > 0) {
    improvedBenchmarkInfo = "\n\n"
    improvedBenchmarkInfo +=
      "| Benchmark File :: Function | Original Runtime | Expected New Runtime | Speedup |\n"
    improvedBenchmarkInfo += "| :--- | ---: | ---: | ---: |\n"

    for (const detail of improvedBenchmarks) {
      const benchmarkName = `${detail.benchmark_name}::${detail.test_function}`
      improvedBenchmarkInfo += `| ${benchmarkName} | ${detail.original_timing} | ${detail.expected_new_timing} | **${detail.speedup_percent.toFixed(2)}%** |\n`
    }
  }

  // Build degraded benchmarks table if there are any
  let degradedBenchmarkInfo = ""
  if (degradedBenchmarks.length > 0) {
    degradedBenchmarkInfo = "\n\n"
    degradedBenchmarkInfo +=
      "| Benchmark File :: Function | Original Runtime | Expected New Runtime | Slowdown |\n"
    degradedBenchmarkInfo += "| :--- | ---: | ---: | ---: |\n"

    for (const detail of degradedBenchmarks) {
      const benchmarkName = `${detail.benchmark_name}::${detail.test_function}`
      // Use absolute value to show slowdown as a positive percentage
      const slowdownPercent = Math.abs(detail.speedup_percent)
      degradedBenchmarkInfo += `| ${benchmarkName} | ${detail.original_timing} | ${detail.expected_new_timing} | **${slowdownPercent.toFixed(2)}%** |\n`
    }
  }

  // Replace placeholders in template
  let result = getPrBenchmarkInfoTemplate()

  // Replace improved benchmark info or remove the section if no improvements
  if (improvedBenchmarks.length > 0) {
    result = result.replace(/\{benchmark_info_improved\}/g, improvedBenchmarkInfo)
  } else {
    // Remove the entire improved section including header
    result = result.replace(
      /###\s+⚡️\s+This change will improve the performance of the following benchmarks:[\s\S]*?\{benchmark_info_improved\}\s*/g,
      "",
    )
  }
  // Replace degraded benchmark info or remove the section if no degradations
  if (degradedBenchmarks.length > 0) {
    result = result.replace(/\{benchmark_info_degraded\}/g, degradedBenchmarkInfo)
  } else {
    // Remove the entire degraded section including header
    result = result.replace(
      /###\s+🔻\s+This change will degrade the performance of the following benchmarks:[\s\S]*?\{benchmark_info_degraded\}\s*/g,
      "",
    )
  }
  return result
}

// Update the buildResultHeader function to use the new benchmark info function
export function buildResultHeader(fields: PrCommentFields, isUnifiedReview?: boolean): string {
  const template = isUnifiedReview ? getPrReviewHeaderTemplate() : getPrHeaderTemplate()

  return template
    .replace(/\{best_runtime}/g, fields.best_runtime)
    .replace(/\{original_runtime}/g, fields.original_runtime)
    .replace(/\{function_name}/g, fields.function_name)
    .replace(/\{file_path}/g, fields.file_path)
    .replace(/\{speedup_x}/g, fields.speedup_x)
    .replace(/\{speedup_pct}/g, fields.speedup_pct)
    .replace(/\{num_runs}/g, fields.loop_count)
}

export function buildResultDetails(fields: PrCommentFields, isCollapsed: boolean = false): string {
  return isCollapsed
    ? `${getPrDetailsTemplateCollapsed().replace(
        /\{optimization_explanation}/g,
        fields.optimization_explanation,
      )}\n`
    : `${getPrDetailsTemplate().replace(
        /\{optimization_explanation}/g,
        fields.optimization_explanation,
      )}\n`
}
export function buildResultFooter(newBranchName: string): string {
  return (
    `To edit these changes ` +
    `\`git checkout ${newBranchName}\` and push.\n\n` +
    `[![Codeflash](https://img.shields.io/badge/Optimized%20with-Codeflash-yellow?style=flat&color=%23ffc428&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgwIiBoZWlnaHQ9ImF1dG8iIHZpZXdCb3g9IjAgMCA0ODAgMjgwIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTI4Ni43IDAuMzc4NDE4SDIwMS43NTFMNTAuOTAxIDE0OC45MTFIMTM1Ljg1MUwwLjk2MDkzOCAyODEuOTk5SDk1LjQzNTJMMjgyLjMyNCA4OS45NjE2SDE5Ni4zNDVMMjg2LjcgMC4zNzg0MThaIiBmaWxsPSIjRkZDMDQzIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMzExLjYwNyAwLjM3ODkwNkwyNTguNTc4IDU0Ljk1MjZIMzc5LjU2N0w0MzIuMzM5IDAuMzc4OTA2SDMxMS42MDdaIiBmaWxsPSIjMEIwQTBBIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMzA5LjU0NyA4OS45NjAxTDI1Ni41MTggMTQ0LjI3NkgzNzcuNTA2TDQzMC4wMjEgODkuNzAyNkgzMDkuNTQ3Vjg5Ljk2MDFaIiBmaWxsPSIjMEIwQTBBIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMjQyLjg3MyAxNjQuNjZMMTg5Ljg0NCAyMTkuMjM0SDMxMC44MzNMMzYzLjM0NyAxNjQuNjZIMjQyLjg3M1oiIGZpbGw9IiMwQjBBMEEiLz4KPC9zdmc+Cg==)](https://codeflash.ai)`
  )
}

export function buildResultTestReport(
  fields: PrCommentFields,
  existingTests: string,
  generatedTests: string,
  coverage_message: string,
  replayTests: string,
  concolicTests: string,
): string {
  const reportTableDict: ReportTable = fields.report_table

  let reportTableMd: string = ""
  // Initialize the Markdown table
  reportTableMd += "| Test                        | Status            |\n"
  reportTableMd += "| --------------------------- | ----------------- |\n"

  // Loop through each test type and construct the table rows
  for (const [testType, { passed = 0, failed = 0 }] of Object.entries(reportTableDict)) {
    if (testType.includes("🎨")) {
      continue
    }
    let status = ""
    let detailsNote = ""

    // Determine the status based on passed counts
    if (passed > 0) {
      status = `✅ **${passed} Passed**`
    } else {
      status = "🔘 **None Found**"
    }

    // If there are details, note that they are available below
    if (passed > 0 && (testType.includes("Existing") || testType.includes("Generated"))) {
      detailsNote = "See below"
    } else {
      detailsNote = ""
    }

    // Add the row to the Markdown table
    reportTableMd += `| ${testType} | ${status} |\n`
  }
  reportTableMd += `|📊 Tests Coverage       | ${coverage_message} |\n`

  // Add detailed test outputs below the table
  for (const [testType, { passed = 0, failed = 0 }] of Object.entries(reportTableDict)) {
    // Only include details for Existing and Generated tests with results
    if (
      passed > 0 &&
      (testType.includes("Existing") ||
        testType.includes("Generated") ||
        testType.includes("Replay") ||
        testType.includes("Concolic"))
    ) {
      // Add a heading for the test type details
      reportTableMd += `<details>\n`

      // Extract emoji if present at the start, then format as "[emoji] Click to see [name]"
      const emojiMatch = /^(\p{Emoji_Presentation}|\p{Emoji}\uFE0F?)/u.exec(testType)
      if (emojiMatch) {
        const emoji = emojiMatch[0]
        const testName = testType.slice(emoji.length).trim()
        reportTableMd += `<summary>${emoji} Click to see ${testName}</summary>\n\n`
      } else {
        reportTableMd += `<summary>Click to see ${testType}</summary>\n\n`
      }

      // Include the relevant test code
      if (testType.includes("Existing")) {
        reportTableMd += existingTests.trim()
        reportTableMd += "\n"
      } else if (testType.includes("Replay")) {
        reportTableMd += replayTests.trim()
        reportTableMd += "\n"
      } else if (testType.includes("Concolic")) {
        reportTableMd += concolicTests.trim()
        reportTableMd += "\n"
      } else if (testType.includes("Generated")) {
        const trimmedGeneratedTests = generatedTests.trim()
        // Check if generatedTests already contains backticks
        if (!trimmedGeneratedTests.includes("`")) {
          // Wrap in Python markdown block
          reportTableMd += `\`\`\`python\n${trimmedGeneratedTests}\n\`\`\``
        } else {
          reportTableMd += trimmedGeneratedTests
        }
        reportTableMd += "\n"
      } else {
        reportTableMd += "_No additional details available._\n"
      }

      reportTableMd += `\n</details>\n\n`
    }
  }

  // Add the final markdown content (e.g., the feedback section)
  const finalMarkdown = reportTableMd

  return getPrTestReportTemplate().replace(/\{report_table}/g, finalMarkdown)
}

// Enhanced parser that supports both metadata and legacy regex parsing
export function parseAndCreateOptimizationsDict(
  prBody: string,
  prComments: Array<{ body: string }>,
): Record<string, Set<string>> {
  const optimizations: Record<string, Set<string>> = {}
  const textsToParse = [prBody, ...prComments.map(comment => comment.body)]

  // New metadata regex for HTML comments
  const metadataRegex = /<!--\s*CODEFLASH_OPTIMIZATION:\s*({.*?})\s*-->/g

  for (const text of textsToParse) {
    // First, try to parse new metadata format
    let metadataMatch
    while ((metadataMatch = metadataRegex.exec(text)) !== null) {
      try {
        const metadata = JSON.parse(metadataMatch[1])
        const functionName = metadata.function
        const filePath = metadata.file

        if (functionName && filePath) {
          optimizations[filePath] ||= new Set()
          optimizations[filePath].add(functionName)
        }
      } catch (e) {
        console.warn("Failed to parse optimization metadata:", metadataMatch[1])
      }
    }

    // Fallback to legacy regex parsing for backward compatibility
    let legacyMatch
    while ((legacyMatch = summaryLinesRegex.exec(text)) !== null) {
      const functionName = legacyMatch[3]
      const filePath = legacyMatch[4]

      if (functionName && filePath) {
        optimizations[filePath] ||= new Set()
        optimizations[filePath].add(functionName)
      }
    }
  }

  return optimizations
}

// Helper function to extract rich metadata from comments (future use)
export function parseOptimizationMetadata(
  prBody: string,
  prComments: Array<{ body: string }>,
): Array<{
  function: string
  file: string
  speedup_pct: string
  speedup_x: string
  original_runtime: string
  best_runtime: string
  optimization_type: string
  timestamp: string
  version: string
}> {
  const optimizations = []
  const textsToParse = [prBody, ...prComments.map(comment => comment.body)]
  const metadataRegex = /<!--\s*CODEFLASH_OPTIMIZATION:\s*({.*?})\s*-->/g

  for (const text of textsToParse) {
    let match
    while ((match = metadataRegex.exec(text)) !== null) {
      try {
        const metadata = JSON.parse(match[1])
        optimizations.push(metadata)
      } catch (e) {
        console.warn("Failed to parse optimization metadata:", match[1])
      }
    }
  }

  return optimizations
}

export function buildDependentPrTitle(
  functionName: string,
  speedupPct: string,
  speedupX: string,
  pullNumber: number,
  baseBranch: string,
): string {
  return `${buildPrTitle(functionName, speedupPct, speedupX)} in PR #${pullNumber} (\`${baseBranch}\`)`
}

export function buildPrTitle(functionName: string, speedupPct: string, speedupX: string): string {
  const type = functionName.includes(".") ? "method" : "function"
  let speedupValue = 0
  if (speedupPct.includes("%")) {
    speedupValue = parseInt(speedupPct.replace("%", ""))
  }
  // hide percent over 1000
  const speed = speedupValue > 1000 ? speedupX : speedupPct
  return `⚡️ Speed up ${type} \`${functionName}\` by ${speed}`
}

export function originalPRComment(
  prCommentFields: PrCommentFields,
  newPrNumber: string,
  baseBranch: string,
  optimizationReview: string,
): string {
  const prCommentHeader = buildResultHeader(prCommentFields)
  let optReviewBadge = generateOptimizationReviewTemplate(optimizationReview)
  optReviewBadge &&= `\n\n${optReviewBadge}\n`
  const isMediumReview = optimizationReview === OptimizationReview.MEDIUM
  const reviewSection = isMediumReview
    ? `#### A new Optimization Review has been created.\n\n🔗 [Review here](https://app.codeflash.ai/review-optimizations/${newPrNumber})`
    : `#### A dependent PR with the suggested changes has been created. Please review:\n\n- ### #${newPrNumber}`
  return `
  #### ⚡️ Codeflash found optimizations for this PR
${prCommentHeader}
${reviewSection}
${
  !isMediumReview
    ? `If you approve, it will be merged into this PR (branch \`${baseBranch}\`).
`
    : ""
}${optReviewBadge}`
}
