// Copyright 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: GPL-3.0-or-later

package admin

import (
	"fmt"
	"net/http"

	"forgejo.org/models/issues"
	"forgejo.org/models/moderation"
	repo_model "forgejo.org/models/repo"
	"forgejo.org/models/user"
	"forgejo.org/modules/base"
	"forgejo.org/services/context"
	moderation_service "forgejo.org/services/moderation"
)

const (
	tplModerationReports       base.TplName = "admin/moderation/reports"
	tplModerationReportDetails base.TplName = "admin/moderation/report_details"
)

// AbuseReports renders the reports overview page from admin moderation section.
func AbuseReports(ctx *context.Context) {
	ctx.Data["Title"] = ctx.Tr("admin.moderation.reports")
	ctx.Data["PageIsAdminModerationReports"] = true

	reports, err := moderation.GetOpenReports(ctx)
	if err != nil {
		ctx.ServerError("Failed to load abuse reports", err)
		return
	}

	ctx.Data["Reports"] = reports
	ctx.Data["AbuseCategories"] = moderation.AbuseCategoriesTranslationKeys
	ctx.Data["GhostUserName"] = user.GhostUserName

	ctx.HTML(http.StatusOK, tplModerationReports)
}

// AbuseReportDetails renders a report details page opened from the reports overview from admin moderation section.
func AbuseReportDetails(ctx *context.Context) {
	ctx.Data["Title"] = ctx.Tr("admin.moderation.reports")
	ctx.Data["PageIsAdminModerationReports"] = true

	ctx.Data["Type"] = ctx.ParamsInt64(":type")
	ctx.Data["ID"] = ctx.ParamsInt64(":id")

	contentType := moderation.ReportedContentType(ctx.ParamsInt64(":type"))

	if !contentType.IsValid() {
		ctx.Flash.Error("Invalid content type")
		return
	}

	reports, err := moderation.GetOpenReportsByTypeAndContentID(ctx, contentType, ctx.ParamsInt64(":id"))
	if err != nil {
		ctx.ServerError("Failed to load reports", err)
		return
	}
	if len(reports) == 0 {
		// something is wrong
		ctx.HTML(http.StatusOK, tplModerationReportDetails)
		return
	}

	ctx.Data["Reports"] = reports
	ctx.Data["AbuseCategories"] = moderation.AbuseCategoriesTranslationKeys
	ctx.Data["GhostUserName"] = user.GhostUserName

	ctx.Data["GetShadowCopyMap"] = moderation_service.GetShadowCopyMap

	if err = setReportedContentDetails(ctx, reports[0]); err != nil {
		if user.IsErrUserNotExist(err) || issues.IsErrCommentNotExist(err) || issues.IsErrIssueNotExist(err) || repo_model.IsErrRepoNotExist(err) {
			ctx.Data["ContentReference"] = ctx.Tr("admin.moderation.deleted_content_ref", reports[0].ContentType, reports[0].ContentID)
		} else {
			ctx.ServerError("Failed to load reported content details", err)
			return
		}
	}

	ctx.HTML(http.StatusOK, tplModerationReportDetails)
}

// setReportedContentDetails adds some values into context data for the given report
// (icon name, a reference, the URL and in case of issues and comments also the poster name).
func setReportedContentDetails(ctx *context.Context, report *moderation.AbuseReportDetailed) error {
	contentReference := ""
	var contentURL string
	var poster string
	contentType := report.ContentType
	contentID := report.ContentID

	ctx.Data["ContentTypeIconName"] = report.ContentTypeIconName()

	switch contentType {
	case moderation.ReportedContentTypeUser:
		reportedUser, err := user.GetUserByID(ctx, contentID)
		if err != nil {
			return err
		}

		contentReference = reportedUser.Name
		contentURL = reportedUser.HomeLink()
	case moderation.ReportedContentTypeRepository:
		repo, err := repo_model.GetRepositoryByID(ctx, contentID)
		if err != nil {
			return err
		}

		contentReference = repo.FullName()
		contentURL = repo.Link()
	case moderation.ReportedContentTypeIssue:
		issue, err := issues.GetIssueByID(ctx, contentID)
		if err != nil {
			return err
		}
		if err = issue.LoadRepo(ctx); err != nil {
			return err
		}
		if err = issue.LoadPoster(ctx); err != nil {
			return err
		}
		if issue.Poster != nil {
			poster = issue.Poster.Name
		}

		contentReference = fmt.Sprintf("%s#%d", issue.Repo.FullName(), issue.Index)
		contentURL = issue.Link()
	case moderation.ReportedContentTypeComment:
		comment, err := issues.GetCommentByID(ctx, contentID)
		if err != nil {
			return err
		}
		if err = comment.LoadIssue(ctx); err != nil {
			return err
		}
		if err = comment.Issue.LoadRepo(ctx); err != nil {
			return err
		}
		if err = comment.LoadPoster(ctx); err != nil {
			return err
		}
		if comment.Poster != nil {
			poster = comment.Poster.Name
		}

		contentURL = comment.Link(ctx)
		contentReference = contentURL
	}

	ctx.Data["ContentReference"] = contentReference
	ctx.Data["ContentURL"] = contentURL
	ctx.Data["Poster"] = poster
	return nil
}
