package actions

import (
	"context"

	gitea_actions_model "code.gitea.io/gitea/models/actions"
	"code.gitea.io/gitea/models/db"
	gitea_repo_model "code.gitea.io/gitea/models/repo"
	"xorm.io/builder"
)

func InsertRun(ctx context.Context, run *gitea_actions_model.ActionRun, jobs []*gitea_actions_model.ActionRunJob) error {
	ctx, commiter, err := db.TxContext(ctx)
	if err != nil {
		return err
	}
	defer commiter.Close()

	index, err := db.GetNextResourceIndex(ctx, "action_run_index", run.RepoID)
	if err != nil {
		return err
	}
	run.Index = index
	run.ID = 0

	if err := db.Insert(ctx, run); err != nil {
		return err
	}

	if run.Repo == nil {
		repo, err := gitea_repo_model.GetRepositoryByID(ctx, run.RepoID)
		if err != nil {
			return err
		}
		run.Repo = repo
	}

	if err := updateRepoRunsNumbers(ctx, run.Repo); err != nil {
		return err
	}

	runJobs := make([]*gitea_actions_model.ActionRunJob, 0, len(jobs))
	for _, job := range jobs {
		runJobs = append(runJobs, &gitea_actions_model.ActionRunJob{
			RunID:             run.ID,
			RepoID:            run.RepoID,
			OwnerID:           run.OwnerID,
			CommitSHA:         run.CommitSHA,
			IsForkPullRequest: run.IsForkPullRequest,
			Name:              job.Name,
			WorkflowPayload:   job.WorkflowPayload,
			JobID:             job.JobID,
			Needs:             job.Needs,
			RunsOn:            job.RunsOn,
			Status:            gitea_actions_model.StatusWaiting,
		})

	}
	if err := db.Insert(ctx, runJobs); err != nil {
		return err
	}

	if err := gitea_actions_model.IncreaseTaskVersion(ctx, run.OwnerID, run.RepoID); err != nil {
		return err
	}

	return commiter.Commit()
}

func updateRepoRunsNumbers(ctx context.Context, repo *gitea_repo_model.Repository) error {
	_, err := db.GetEngine(ctx).ID(repo.ID).
		SetExpr("num_action_runs",
			builder.Select("count(*)").From("action_run").
				Where(builder.Eq{"repo_id": repo.ID}),
		).
		SetExpr("num_closed_action_runs",
			builder.Select("count(*)").From("action_run").
				Where(builder.Eq{
					"repo_id": repo.ID,
				}.And(
					builder.In("status",
						gitea_actions_model.StatusSuccess,
						gitea_actions_model.StatusFailure,
						gitea_actions_model.StatusCancelled,
						gitea_actions_model.StatusSkipped,
					),
				),
				),
		).
		Update(repo)
	return err
}
