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

package forgejo_migrations

import (
	"xorm.io/xorm"
	"xorm.io/xorm/schemas"
)

func init() {
	registerMigration(&Migration{
		Description: "rework indexes on table action",
		Upgrade:     reworkActionIndexes,
	})
}

type v14bAction struct {
	ID          int64 `xorm:"pk autoincr"`
	UserID      int64 // Receiver user id.
	OpType      int
	ActUserID   int64 // Action user id.
	RepoID      int64
	CommentID   int64 `xorm:"INDEX"`         // indexed to support `DeleteIssueActions`
	CreatedUnix int64 `xorm:"created INDEX"` // indexed to support `DeleteOldActions`
}

// TableName sets the name of this table
func (a *v14bAction) TableName() string {
	return "action"
}

// TableIndices implements xorm's TableIndices interface.  It is used here to ensure indexes with specified column order
// are created, which can't be created through xorm tags on the struct.
func (a *v14bAction) TableIndices() []*schemas.Index {
	// Index to support getUserHeatmapData, which searches for data that is visible-to (user_id) and performed-by
	// (act_user_id) a user, but only includes visible repos (repo_id).
	actUserIndex := schemas.NewIndex("au_r_c_u", schemas.IndexType)
	actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id")

	// GetFeeds is a common access point to Action and requires that all action feeds be queried based upon one of
	// user_id (opts.RequestedUser), repo_id (opts.RequestedTeam... kinda), and/or repo_id (opts.RequestedRepo), and
	// then the results are ordered by created_unix and paginated.  The most efficient indexes to support those queries
	// are:
	requestedUser := schemas.NewIndex("user_id_created_unix", schemas.IndexType)
	requestedUser.AddColumn("user_id", "created_unix")
	requestedRepo := schemas.NewIndex("repo_id_created_unix", schemas.IndexType)
	requestedRepo.AddColumn("repo_id", "created_unix")

	// To support `DeleteIssueActions` search for createissue / createpullrequest actions; this isn't a great search
	// because `DeleteIssueActions` searches by `content` as well, but it should be sufficient performance-wise for
	// infrequent deleting of issues.
	repoOpType := schemas.NewIndex("repo_id_op_type", schemas.IndexType)
	repoOpType.AddColumn("repo_id", "op_type")

	indices := []*schemas.Index{actUserIndex, requestedUser, requestedRepo, repoOpType}

	return indices
}

func reworkActionIndexes(x *xorm.Engine) error {
	if err := dropIndexIfExists(x, "action", "IDX_action_c_u"); err != nil {
		return err
	}
	if err := dropIndexIfExists(x, "action", "IDX_action_r_u"); err != nil {
		return err
	}
	if err := dropIndexIfExists(x, "action", "IDX_action_user_id"); err != nil {
		return err
	}

	return x.Sync(new(v14bAction)) // nosemgrep:xorm-sync-missing-ignore-drop-indices
}
