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

package repo

import (
	"context"
	"strconv"
	"strings"

	"forgejo.org/models/moderation"
	"forgejo.org/modules/json"
	"forgejo.org/modules/timeutil"
)

// RepositoryData represents a trimmed down repository that is used for preserving
// only the fields needed for abusive content reports (mainly string fields).
type RepositoryData struct {
	OwnerID     int64
	OwnerName   string
	Name        string
	Description string
	Website     string
	Topics      []string
	Avatar      string
	CreatedUnix timeutil.TimeStamp
	UpdatedUnix timeutil.TimeStamp
}

// Implements GetFieldsMap() from ShadowCopyData interface, returning a list of <key, value> pairs
// to be used when rendering the shadow copy for admins reviewing the corresponding abuse report(s).
func (rd RepositoryData) GetFieldsMap() []moderation.ShadowCopyField {
	return []moderation.ShadowCopyField{
		{Key: "OwnerID", Value: strconv.FormatInt(rd.OwnerID, 10)},
		{Key: "OwnerName", Value: rd.OwnerName},
		{Key: "Name", Value: rd.Name},
		{Key: "Description", Value: rd.Description},
		{Key: "Website", Value: rd.Website},
		{Key: "Topics", Value: strings.Join(rd.Topics, ", ")},
		{Key: "Avatar", Value: rd.Avatar},
		{Key: "CreatedUnix", Value: rd.CreatedUnix.AsLocalTime().String()},
		{Key: "UpdatedUnix", Value: rd.UpdatedUnix.AsLocalTime().String()},
	}
}

// Implements GetAbuserID() from ShadowCopyData interface, returning the value of OwnerID field.
func (rd *RepositoryData) GetAbuserID() (int64, bool) {
	return rd.OwnerID, true
}

// newRepositoryData creates a trimmed down repository to be used just to create a JSON structure
// (keeping only the fields relevant for moderation purposes)
func newRepositoryData(repo *Repository) RepositoryData {
	return RepositoryData{
		OwnerID:     repo.OwnerID,
		OwnerName:   repo.OwnerName,
		Name:        repo.Name,
		Description: repo.Description,
		Website:     repo.Website,
		Topics:      repo.Topics,
		Avatar:      repo.Avatar,
		CreatedUnix: repo.CreatedUnix,
		UpdatedUnix: repo.UpdatedUnix,
	}
}

// IfNeededCreateShadowCopyForRepository checks if for the given repository there are any reports of abusive content submitted
// and if found a shadow copy of relevant repository fields will be stored into DB and linked to the above report(s).
// This function should be called when a repository is deleted or updated.
func IfNeededCreateShadowCopyForRepository(ctx context.Context, repo *Repository, forUpdates bool) error {
	shadowCopyNeeded, err := moderation.IsShadowCopyNeeded(ctx, moderation.ReportedContentTypeRepository, repo.ID)
	if err != nil {
		return err
	}

	if shadowCopyNeeded {
		if forUpdates {
			// get the unmodified repository fields
			repo, err = GetRepositoryByID(ctx, repo.ID)
			if err != nil {
				return err
			}
		}
		repoData := newRepositoryData(repo)
		content, err := json.Marshal(repoData)
		if err != nil {
			return err
		}
		return moderation.CreateShadowCopyForRepository(ctx, repo.ID, string(content))
	}

	return nil
}
