// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package actions

import (
	"net/http"
	"slices"
	"strconv"

	actions_model "gitea.dev/models/actions"
	"gitea.dev/models/perm"
	repo_model "gitea.dev/models/repo"
	"gitea.dev/models/unit"
	"gitea.dev/modules/templates"
	"gitea.dev/modules/util"
	"gitea.dev/services/context"
)

const (
	tplOrgSettingsActionsGeneral  templates.TplName = "org/settings/actions_general"
	tplUserSettingsActionsGeneral templates.TplName = "user/settings/actions_general"
)

// ParseMaxTokenPermissions parses the maximum token permissions from form values
func ParseMaxTokenPermissions(ctx *context.Context) *repo_model.ActionsTokenPermissions {
	parseMaxPerm := func(unitType unit.Type) perm.AccessMode {
		value := ctx.FormString("max_unit_access_mode_" + strconv.Itoa(int(unitType)))
		switch value {
		case "write":
			return perm.AccessModeWrite
		case "read":
			return perm.AccessModeRead
		default:
			return perm.AccessModeNone
		}
	}
	ret := new(repo_model.MakeActionsTokenPermissions(perm.AccessModeNone))
	for _, ut := range repo_model.ActionsTokenUnitTypes {
		ret.UnitAccessModes[ut] = parseMaxPerm(ut)
	}
	return ret
}

// GeneralSettings renders the actions general settings page
func GeneralSettings(ctx *context.Context) {
	ctx.Data["Title"] = ctx.Tr("actions.actions")

	rCtx, err := getRunnersCtx(ctx)
	if err != nil {
		ctx.ServerError("getRunnersCtx", err)
		return
	}

	if rCtx.IsOrg {
		ctx.Data["PageIsOrgSettings"] = true
		ctx.Data["PageIsOrgSettingsActionsGeneral"] = true
	} else if rCtx.IsUser {
		ctx.Data["PageIsUserSettings"] = true
		ctx.Data["PageIsUserSettingsActionsGeneral"] = true
	} else {
		ctx.NotFound(nil)
		return
	}

	// Load User/Org Actions Config
	actionsCfg, err := actions_model.GetOwnerActionsConfig(ctx, rCtx.OwnerID)
	if err != nil {
		ctx.ServerError("GetOwnerActionsConfig", err)
		return
	}

	ctx.Data["TokenPermissionMode"] = actionsCfg.TokenPermissionMode
	ctx.Data["TokenPermissionModePermissive"] = repo_model.ActionsTokenPermissionModePermissive
	ctx.Data["TokenPermissionModeRestricted"] = repo_model.ActionsTokenPermissionModeRestricted
	ctx.Data["MaxTokenPermissions"] = actionsCfg.MaxTokenPermissions
	if actionsCfg.MaxTokenPermissions == nil {
		ctx.Data["MaxTokenPermissions"] = (&repo_model.ActionsConfig{}).GetMaxTokenPermissions()
	}
	ctx.Data["EnableMaxTokenPermissions"] = actionsCfg.MaxTokenPermissions != nil

	// Load Allowed Repositories
	allowedRepos, err := repo_model.GetOwnerRepositoriesByIDs(ctx, rCtx.OwnerID, actionsCfg.AllowedCrossRepoIDs)
	if err != nil {
		ctx.ServerError("GetOwnerRepositoriesByIDs", err)
		return
	}

	ctx.Data["AllowedRepos"] = allowedRepos
	ctx.Data["OwnerID"] = rCtx.OwnerID

	if rCtx.IsOrg {
		ctx.HTML(http.StatusOK, tplOrgSettingsActionsGeneral)
	} else {
		ctx.HTML(http.StatusOK, tplUserSettingsActionsGeneral)
	}
}

// UpdateGeneralSettings responses for actions general settings page
func UpdateGeneralSettings(ctx *context.Context) {
	rCtx, err := getRunnersCtx(ctx)
	if err != nil {
		ctx.ServerError("getRunnersCtx", err)
		return
	}

	if !rCtx.IsOrg && !rCtx.IsUser {
		ctx.NotFound(nil)
		return
	}

	actionsCfg, err := actions_model.GetOwnerActionsConfig(ctx, rCtx.OwnerID)
	if err != nil {
		ctx.ServerError("GetOwnerActionsConfig", err)
		return
	}

	if ctx.FormBool("cross_repo_add_target") {
		targetRepoName := ctx.FormString("cross_repo_add_target_name")
		if targetRepoName != "" {
			targetRepo, err := repo_model.GetRepositoryByName(ctx, rCtx.OwnerID, targetRepoName)
			if err != nil {
				if repo_model.IsErrRepoNotExist(err) {
					ctx.JSONError("Repository doesn't exist")
					return
				}
				ctx.ServerError("GetRepositoryByName", err)
				return
			}
			if !slices.Contains(actionsCfg.AllowedCrossRepoIDs, targetRepo.ID) {
				actionsCfg.AllowedCrossRepoIDs = append(actionsCfg.AllowedCrossRepoIDs, targetRepo.ID)
			}
		}
	}

	if crossRepoRemoveTargetID := ctx.FormInt64("cross_repo_remove_target_id"); crossRepoRemoveTargetID != 0 {
		actionsCfg.AllowedCrossRepoIDs = util.SliceRemoveAll(actionsCfg.AllowedCrossRepoIDs, crossRepoRemoveTargetID)
	}

	// Update Token Permission Mode
	tokenPermissionMode, tokenPermissionModeValid := util.EnumValue(repo_model.ActionsTokenPermissionMode(ctx.FormString("token_permission_mode")))
	if tokenPermissionModeValid {
		actionsCfg.TokenPermissionMode = tokenPermissionMode
		enableMaxPermissions := ctx.FormBool("enable_max_permissions")
		// Update Maximum Permissions (radio buttons: none/read/write)
		if enableMaxPermissions {
			actionsCfg.MaxTokenPermissions = ParseMaxTokenPermissions(ctx)
		} else {
			actionsCfg.MaxTokenPermissions = nil
		}
	}

	if err := actions_model.SetOwnerActionsConfig(ctx, rCtx.OwnerID, actionsCfg); err != nil {
		ctx.ServerError("SetOwnerActionsConfig", err)
		return
	}

	ctx.Flash.Success(ctx.Tr("settings.saved_successfully"))
	ctx.JSONRedirect("") // use JSONRedirect because frontend uses form-fetch-action
}
