// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package code
import (
	"bytes"
	"context"
	"html/template"
	"strings"
	"code.gitea.io/gitea/modules/highlight"
	"code.gitea.io/gitea/modules/indexer/code/internal"
	"code.gitea.io/gitea/modules/timeutil"
	"code.gitea.io/gitea/services/gitdiff"
)
// Result a search result to display
type Result struct {
	RepoID      int64
	Filename    string
	CommitID    string
	UpdatedUnix timeutil.TimeStamp
	Language    string
	Color       string
	Lines       []ResultLine
}
type ResultLine struct {
	Num              int
	FormattedContent template.HTML
}
type SearchResultLanguages = internal.SearchResultLanguages
type SearchOptions = internal.SearchOptions
func indices(content string, selectionStartIndex, selectionEndIndex int) (int, int) {
	startIndex := selectionStartIndex
	numLinesBefore := 0
	for ; startIndex > 0; startIndex-- {
		if content[startIndex-1] == '\n' {
			if numLinesBefore == 1 {
				break
			}
			numLinesBefore++
		}
	}
	endIndex := selectionEndIndex
	numLinesAfter := 0
	for ; endIndex < len(content); endIndex++ {
		if content[endIndex] == '\n' {
			if numLinesAfter == 1 {
				break
			}
			numLinesAfter++
		}
	}
	return startIndex, endIndex
}
func writeStrings(buf *bytes.Buffer, strs ...string) error {
	for _, s := range strs {
		_, err := buf.WriteString(s)
		if err != nil {
			return err
		}
	}
	return nil
}
const (
	highlightTagStart = ""
	highlightTagEnd   = ""
)
func HighlightSearchResultCode(filename string, lineNums []int, highlightRanges [][3]int, code string) []ResultLine {
	hcd := gitdiff.NewHighlightCodeDiff()
	hcd.CollectUsedRunes(code)
	startTag, endTag := hcd.NextPlaceholder(), hcd.NextPlaceholder()
	hcd.PlaceholderTokenMap[startTag] = highlightTagStart
	hcd.PlaceholderTokenMap[endTag] = highlightTagEnd
	// we should highlight the whole code block first, otherwise it doesn't work well with multiple line highlighting
	hl, _ := highlight.Code(filename, "", code)
	conv := hcd.ConvertToPlaceholders(string(hl))
	convLines := strings.Split(conv, "\n")
	// each highlightRange is of the form [line number, start pos, end pos]
	for _, highlightRange := range highlightRanges {
		ln, start, end := highlightRange[0], highlightRange[1], highlightRange[2]
		line := convLines[ln]
		if line == "" || len(line) <= start || len(line) < end {
			continue
		}
		sb := strings.Builder{}
		count := -1
		isOpen := false
		for _, r := range line {
			if token, ok := hcd.PlaceholderTokenMap[r];
			// token was not found
			!ok ||
				// token was marked as used
				token == "" ||
				// the token is not an valid html tag emited by chroma
				!(len(token) > 6 && (token[0:5] == "