import escape from 'escape-html'
import * as Diff from 'diff'
import {type Repository} from './dataTypes.ts'
import { type ReposConfiguration } from './configTypes.ts'

type Diffs = ReturnType<Repository['commits']['get']>['diffs']


const getGitDiffsFromPatchText = (patchText: string): Diffs => {
  const lines = patchText.split("\n")
  const hunks: Diffs = []
  let previousHunk = -1
  const filenameRegex = RegExp(/diff --git a\/(.*?) b\/(.*?)/)
  const lineNumberRegex = RegExp(/@@ -(.*?)[,| ].*/)
  let previousFilename = ''
  let currentFilename = ''
  let skipFourStartingAt = -1
  lines.forEach((line, index) => {
    if (line.startsWith("diff")) {
      previousFilename = currentFilename
      currentFilename = line.match(filenameRegex)[1]
      if (previousHunk !== -1) {
        skipFourStartingAt = index
      }
    }
    if (line.startsWith("@@") || index == lines.length - 1) {
      if (previousHunk === -1) {
        previousHunk = index
        return
      }

      let hunkEndIndex = index + 1
      if (skipFourStartingAt !== -1 && skipFourStartingAt < hunkEndIndex) {
        hunkEndIndex = skipFourStartingAt
        skipFourStartingAt = -1
      }
      const lastHunk = lines.slice(previousHunk, hunkEndIndex)

      let lastHunkBefore = lastHunk.filter((line) => {
        return line.startsWith("-") || line.startsWith(" ")
      }).map((str) => {
        if (str.startsWith('-')) { return str.replace("-", "") }
        if (str.startsWith(' ')) { return str.replace(" ", "") }
      }).join("\n")

      let lastHunkAfter = lastHunk.filter((line) => {
        return line.startsWith("+") || line.startsWith(" ")
      }).map((str) => {
        if (str.startsWith('+')) { return str.replace("+", "") }
        if (str.startsWith(' ')) { return str.replace(" ", "") }
      }).join("\n")

      const changeObject = Diff.diffWordsWithSpace(lastHunkBefore, lastHunkAfter)
      let beforeText = ""
      let afterText = ""

      changeObject.forEach((obj) => {
        const numNewLines = obj.value.split('').filter(char => char === '\n').length

        if (!obj.added && !obj.removed) {
          beforeText = beforeText + escape(obj.value)
          afterText = afterText + escape(obj.value)
        }
        if (obj.added) {
          afterText = afterText + "<mark>" + escape(obj.value) + "</mark>"
          if (numNewLines > 0) {
            let insertAt = beforeText.lastIndexOf("\n")
            insertAt = insertAt === -1 ? 0 : insertAt

            beforeText = beforeText.slice(0, insertAt + 1) + (new Array(numNewLines).fill('\u{2063}\n', 0).join('')) + beforeText.slice(insertAt + 1)
          }
        }
        if (obj.removed) {
          beforeText = beforeText + "<mark>" + escape(obj.value) + "</mark>"
          if (numNewLines > 0) {
            let insertAt = afterText.lastIndexOf("\n")
            insertAt = insertAt === -1 ? 0 : insertAt

            afterText = afterText.slice(0, insertAt + 1) + (new Array(numNewLines).fill('\u{2063}\n', 0).join('')) + afterText.slice(insertAt + 1)
          }
        }
      })

      hunks.push({
        fileName: previousFilename !== '' ? previousFilename : currentFilename,
        lineNumber: parseInt(lines[previousHunk].match(lineNumberRegex)[1]),
        beforeText,
        afterText,
      })
      previousFilename = ''
      previousHunk = index
    }
  })

  return hunks
}

const getLocation = (reposConfig: ReposConfiguration, outputDir: string, repoName: string): string => {
  return outputDir + (reposConfig.path || "") + "/" + repoName + ".git"
}

export {
  getGitDiffsFromPatchText,
  getLocation,
}
