"use client"

import { useState, useEffect, useMemo, memo, type ReactNode } from "react"

type SideBySideRow = {
  leftLine: string | null
  leftNum: number | null
  leftType: "removed" | "context" | "empty"
  rightLine: string | null
  rightNum: number | null
  rightType: "added" | "context" | "empty"
}

// Module-level constants to avoid re-creating JSX on every call
const ADDED_INDICATOR = <span className="text-green-500">+</span>
const REMOVED_INDICATOR = <span className="text-red-500">{"\u2212"}</span>

type DiffLineStyle = {
  bgClass: string
  textClass: string
  lineContent: string
  indicator: ReactNode
  borderClass: string
}

function getDiffLineStyle(line: string): DiffLineStyle {
  if (line.startsWith("@@")) {
    return {
      bgClass: "bg-blue-900/30",
      textClass: "text-blue-400",
      lineContent: line,
      indicator: null,
      borderClass: "border-transparent",
    }
  }

  if (line.startsWith("+")) {
    return {
      bgClass: "bg-green-900/40",
      textClass: "text-green-300",
      lineContent: line.substring(1),
      indicator: ADDED_INDICATOR,
      borderClass: "border-green-500",
    }
  }

  if (line.startsWith("-")) {
    return {
      bgClass: "bg-red-900/40",
      textClass: "text-red-300",
      lineContent: line.substring(1),
      indicator: REMOVED_INDICATOR,
      borderClass: "border-red-500",
    }
  }

  if (line.startsWith(" ")) {
    return {
      bgClass: "",
      textClass: "text-zinc-300",
      lineContent: line.substring(1),
      indicator: null,
      borderClass: "border-transparent",
    }
  }

  return {
    bgClass: "",
    textClass: "text-zinc-300",
    lineContent: line,
    indicator: null,
    borderClass: "border-transparent",
  }
}

function getCellStyle(type: "removed" | "added" | "context" | "empty") {
  switch (type) {
    case "removed":
      return "bg-red-900/30 text-red-300"
    case "added":
      return "bg-green-900/30 text-green-300"
    case "empty":
      return "bg-zinc-800/30"
    default:
      return "text-zinc-300"
  }
}

interface DiffViewProps {
  diff: string
}

export const DiffView = memo(function DiffView({ diff }: DiffViewProps) {
  const filteredLines = useMemo(() => {
    const lines = diff.split("\n")
    return lines.filter((line, index) => {
      // Skip empty last line
      if (index === lines.length - 1 && line === "") return false

      // Skip empty additions/deletions
      const isEmptyAddition = line.startsWith("+") && line.substring(1).trim() === ""
      const isEmptyDeletion = line.startsWith("-") && line.substring(1).trim() === ""
      if (line === "+" || line === "-" || isEmptyAddition || isEmptyDeletion) {
        return false
      }

      // Skip diff metadata
      if (line.startsWith("\\ No newline") || line.startsWith("\\")) {
        return false
      }

      return true
    })
  }, [diff])

  return (
    <div className="font-mono text-sm bg-zinc-900 overflow-x-auto">
      {filteredLines.map((line, index) => {
        const { bgClass, textClass, lineContent, indicator, borderClass } = getDiffLineStyle(line)

        return (
          <div
            key={index}
            className={`flex ${bgClass} border-l-2 ${borderClass}`}
          >
            <div className="w-8 flex-shrink-0 text-right pr-2 select-none">
              {indicator}
            </div>
            <pre className={`flex-1 px-2 py-0.5 ${textClass} whitespace-pre`}>
              {lineContent || " "}
            </pre>
          </div>
        )
      })}
    </div>
  )
})

interface SideBySideDiffViewProps {
  originalCode: string
  candidateCode: string
  language: string
}

export const SideBySideDiffView = memo(function SideBySideDiffView({
  originalCode,
  candidateCode,
}: SideBySideDiffViewProps) {
  const [rows, setRows] = useState<SideBySideRow[] | null>(null)

  useEffect(() => {
    import("diff").then(({ diffLines }) => {
      const changes = diffLines(originalCode, candidateCode)
      const result: SideBySideRow[] = []
      let leftNum = 1
      let rightNum = 1

      for (let i = 0; i < changes.length; i++) {
        const change = changes[i]
        const lines = change.value.replace(/\n$/, "").split("\n")

        if (!change.added && !change.removed) {
          // Context lines - appear on both sides
          for (const line of lines) {
            result.push({
              leftLine: line,
              leftNum: leftNum++,
              leftType: "context",
              rightLine: line,
              rightNum: rightNum++,
              rightType: "context",
            })
          }
        } else if (change.removed) {
          // Check if next change is an addition (replacement scenario)
          const next = i + 1 < changes.length ? changes[i + 1] : null
          if (next && next.added) {
            // Side-by-side replacement
            const removedLines = lines
            const addedLines = next.value.replace(/\n$/, "").split("\n")
            const maxLen = Math.max(removedLines.length, addedLines.length)

            for (let j = 0; j < maxLen; j++) {
              result.push({
                leftLine: j < removedLines.length ? removedLines[j] : null,
                leftNum: j < removedLines.length ? leftNum++ : null,
                leftType: j < removedLines.length ? "removed" : "empty",
                rightLine: j < addedLines.length ? addedLines[j] : null,
                rightNum: j < addedLines.length ? rightNum++ : null,
                rightType: j < addedLines.length ? "added" : "empty",
              })
            }
            i++ // Skip the next change since we processed it
          } else {
            // Only removal, no corresponding addition
            for (const line of lines) {
              result.push({
                leftLine: line,
                leftNum: leftNum++,
                leftType: "removed",
                rightLine: null,
                rightNum: null,
                rightType: "empty",
              })
            }
          }
        } else if (change.added) {
          // Only addition, no corresponding removal
          for (const line of lines) {
            result.push({
              leftLine: null,
              leftNum: null,
              leftType: "empty",
              rightLine: line,
              rightNum: rightNum++,
              rightType: "added",
            })
          }
        }
      }

      setRows(result)
    })
  }, [originalCode, candidateCode])

  if (!rows) {
    return (
      <div className="p-4 bg-zinc-900 animate-pulse">
        <div className="h-4 bg-zinc-700 rounded w-3/4 mb-2" />
        <div className="h-4 bg-zinc-700 rounded w-1/2 mb-2" />
        <div className="h-4 bg-zinc-700 rounded w-2/3" />
      </div>
    )
  }

  return (
    <div className="grid grid-cols-2 font-mono text-sm bg-zinc-900">
      <div className="border-r border-zinc-700">
        <div className="px-3 py-1.5 bg-zinc-800 text-xs text-zinc-400 font-medium border-b border-zinc-700">
          Original
        </div>
        <div>
          {rows.map((row, i) => (
            <div key={i} className={`flex ${getCellStyle(row.leftType)}`}>
              <span className="w-10 flex-shrink-0 text-right pr-2 py-0.5 text-zinc-500 select-none text-xs">
                {row.leftNum ?? ""}
              </span>
              <pre className="flex-1 px-2 py-0.5 whitespace-pre overflow-hidden">
                {row.leftLine ?? " "}
              </pre>
            </div>
          ))}
        </div>
      </div>
      <div>
        <div className="px-3 py-1.5 bg-zinc-800 text-xs text-zinc-400 font-medium border-b border-zinc-700">
          Optimized
        </div>
        <div>
          {rows.map((row, i) => (
            <div key={i} className={`flex ${getCellStyle(row.rightType)}`}>
              <span className="w-10 flex-shrink-0 text-right pr-2 py-0.5 text-zinc-500 select-none text-xs">
                {row.rightNum ?? ""}
              </span>
              <pre className="flex-1 px-2 py-0.5 whitespace-pre overflow-hidden">
                {row.rightLine ?? " "}
              </pre>
            </div>
          ))}
        </div>
      </div>
    </div>
  )
})
