package repo

import (
	"fmt"
	"net/http"
	"strings"

	issues_model "code.gitea.io/gitea/models/issues"
	"code.gitea.io/gitea/modules/context"
	"code.gitea.io/gitea/modules/setting"
	"code.gitea.io/gitea/routers/api/v1/utils"
	"code.gitea.io/gitea/services/gitdiff"
	hat_pull_model "code.gitlink.org.cn/Gitlink/gitea_hat.git/models/pull"
	hat_convert "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/convert"
	hat_git "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/git"
	hat_api "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/structs"
	hat_gitdiff "code.gitlink.org.cn/Gitlink/gitea_hat.git/services/gitdiff"
)

func ListPullRequestVersions(ctx *context.APIContext) {
	pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
	if err != nil {
		if issues_model.IsErrPullRequestNotExist(err) {
			ctx.NotFound()
		} else {
			ctx.InternalServerError(err)
		}
		return
	}

	listOptions := utils.GetListOptions(ctx)
	prvs, maxResults, err := hat_pull_model.PullRequestVersions(ctx, pr.ID, &listOptions)
	if err != nil {
		ctx.Error(http.StatusInternalServerError, "PullRequestVersions", err)
		return
	}

	apiPrvs := make([]*hat_api.PullRequestVersion, len(prvs))
	for i := range prvs {
		apiPrvs[i] = hat_convert.ToAPIPullRequestVersion(prvs[i])
	}

	ctx.SetLinkHeader(int(maxResults), listOptions.PageSize)
	ctx.RespHeader().Set("X-Total", fmt.Sprintf("%d", maxResults))
	ctx.RespHeader().Set("X-Total-Count", fmt.Sprintf("%d", maxResults))
	ctx.RespHeader().Set("Access-Control-Expose-Headers", "X-Total-Count, Link, X-Total")

	ctx.JSON(http.StatusOK, &apiPrvs)
}

func GetPullRequestVersionDiff(ctx *context.APIContext) {
	if ctx.Repo.Repository.IsEmpty {
		ctx.NotFound()
		return
	}

	pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
	if err != nil {
		if issues_model.IsErrPullRequestNotExist(err) {
			ctx.NotFound()
		} else {
			ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
		}
		return
	}

	prv, err := hat_pull_model.GetPullRequestVersionByID(ctx, pr.ID, ctx.ParamsInt64(":versionId"))
	if err != nil {
		if issues_model.IsErrPullRequestNotExist(err) {
			ctx.NotFound()
		} else {
			ctx.Error(http.StatusInternalServerError, "GetPullRequestVersionByID", err)
		}
		return
	}

	diffs, err := gitdiff.GetDiff(ctx.Repo.GitRepo, &gitdiff.DiffOptions{
		BeforeCommitID:    prv.BaseCommitID,
		AfterCommitID:     prv.HeadCommitID,
		MaxLines:          setting.Git.MaxGitDiffLines,
		MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
		MaxFiles:          setting.Git.MaxGitDiffFiles,
	})
	if err != nil {
		ctx.Error(http.StatusInternalServerError, "GetDiff", err)
	}

	filepath := ctx.FormString("filepath")
	if filepath == "" {
		ctx.JSON(http.StatusOK, diffs)
	} else {
		targetDiffFile := &hat_gitdiff.DiffFile{}
		for _, file := range diffs.Files {
			if file.Name == filepath {
				if diffString, err := hat_git.GetDiffStringByFilePath(ctx.Repo.GitRepo, prv.BaseCommitID, prv.HeadCommitID, file.Name); err == nil {
					stringArray := strings.Split(diffString, "\n")
					var afterStrings []string
					for _, item := range stringArray {
						switch {
						case strings.HasPrefix(item, "diff --git"):
							continue
						case strings.HasPrefix(item, "index"):
							continue
						case strings.HasPrefix(item, "---"):
							continue
						case strings.HasPrefix(item, "+++"):
							continue
						case strings.HasPrefix(item, "new file mode"):
							continue
						case strings.HasPrefix(item, "deleted file mode"):
							continue
						case strings.HasSuffix(item, "No newline at end of file"):
							continue
						default:
							afterStrings = append(afterStrings, item)
						}
					}
					targetDiffFile.Diff = strings.Join(afterStrings, "\n")
				}
				targetDiffFile.DiffFile = file
				break
			}
		}
		if targetDiffFile.DiffFile == nil {
			ctx.NotFound()
		} else {
			ctx.JSON(http.StatusOK, targetDiffFile)
		}
	}
}
