package org

import (
	"errors"
	"net/http"

	"code.gitea.io/gitea/modules/context"
	api "code.gitea.io/gitea/modules/structs"
	"code.gitea.io/gitea/modules/util"
	"code.gitea.io/gitea/modules/web"
	"code.gitea.io/gitea/routers/api/v1/utils"

	hat_actions_model "code.gitlink.org.cn/Gitlink/gitea_hat.git/models/actions"
	hat_api "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/structs"
	hat_actions_service "code.gitlink.org.cn/Gitlink/gitea_hat.git/services/actions"
)

func DeleteActionsSecret(ctx *context.APIContext) {
	if err := hat_actions_service.DeleteSecretByName(ctx, ctx.Org.Organization.ID, 0, ctx.Params("secretname")); err != nil {
		if errors.Is(err, util.ErrInvalidArgument) {
			ctx.Error(http.StatusBadRequest, "DeleteSecretByName", err)
		} else if errors.Is(err, util.ErrNotExist) {
			ctx.NotFound(err)
		} else {
			ctx.InternalServerError(err)
		}
		return
	}

	ctx.Status(http.StatusNoContent)
}

func CreateActionsSecret(ctx *context.APIContext) {
	opt := web.GetForm(ctx).(*hat_api.CreateSecretOption)
	ownerID := ctx.Org.Organization.ID
	secretName := ctx.Params("secretname")

	v, err := hat_actions_service.GetSecret(ctx, hat_actions_model.FindSecretsOptions{
		OwnerID: ownerID,
		Name:    secretName,
	})
	if err != nil && !errors.Is(err, util.ErrNotExist) {
		ctx.InternalServerError(err)
		return
	}
	if v != nil && v.ID > 0 {
		ctx.Error(http.StatusConflict, "", util.NewAlreadyExistErrorf("secret name %s already exists", secretName))
		return
	}
	if _, err := hat_actions_service.CreateSecret(ctx, ownerID, 0, secretName, opt.Data); err != nil {
		if errors.Is(err, util.ErrInvalidArgument) {
			ctx.Error(http.StatusBadRequest, "CreateSecret", err)
		} else {
			ctx.InternalServerError(err)
		}
		return
	}
	ctx.Status(http.StatusCreated)
}

func UpdateActionsSecret(ctx *context.APIContext) {
	opt := web.GetForm(ctx).(*hat_api.UpdateSecretOption)

	_, err := hat_actions_service.GetSecret(ctx, hat_actions_model.FindSecretsOptions{
		OwnerID: ctx.Org.Organization.ID,
		Name:    ctx.Params("secretname"),
	})
	if err != nil {
		if errors.Is(err, util.ErrNotExist) {
			ctx.Error(http.StatusNotFound, "GetSecret", err)
		} else {
			ctx.InternalServerError(err)
		}
		return
	}

	if opt.Name == "" {
		opt.Name = ctx.Params("secretname")
	}

	_, err = hat_actions_service.UpdateSecret(ctx, ctx.Org.Organization.ID, 0, opt.Name, opt.Data)
	if err != nil {
		if errors.Is(err, util.ErrInvalidArgument) {
			ctx.Error(http.StatusBadRequest, "UpdateSecret", err)
		} else {
			ctx.InternalServerError(err)
		}
		return
	}

	ctx.Status(http.StatusNoContent)

}

func ListActionsSecrets(ctx *context.APIContext) {
	opts := &hat_actions_model.FindSecretsOptions{
		OwnerID:     ctx.Org.Organization.ID,
		ListOptions: utils.GetListOptions(ctx),
	}

	count, err := hat_actions_model.CountSecrets(ctx, opts)
	if err != nil {
		ctx.InternalServerError(err)
		return
	}

	secrets, err := hat_actions_model.FindSecrets(ctx, *opts)
	if err != nil {
		ctx.InternalServerError(err)
		return
	}

	apiSecrets := make([]*api.Secret, len(secrets))
	for k, v := range secrets {
		apiSecrets[k] = &api.Secret{
			Name:    v.Name,
			Created: v.CreatedUnix.AsTime(),
		}
	}

	ctx.SetTotalCountHeader(count)
	ctx.JSON(http.StatusOK, apiSecrets)
}

func GetVariable(ctx *context.APIContext) {
	v, err := hat_actions_service.GetVariable(ctx, hat_actions_model.FindVariablesOpts{
		OwnerID: ctx.Org.Organization.ID,
		Name:    ctx.Params("variablename"),
	})
	if err != nil {
		if errors.Is(err, util.ErrNotExist) {
			ctx.NotFound(err)
		} else {
			ctx.InternalServerError(err)
		}
		return
	}

	variable := &hat_api.ActionVariable{
		OwnerID: v.OwnerID,
		RepoID:  v.RepoID,
		Name:    v.Name,
		Data:    v.Data,
	}

	ctx.JSON(http.StatusOK, variable)
}

func DeleteVariable(ctx *context.APIContext) {
	if err := hat_actions_service.DeleteVariableByName(ctx, ctx.Org.Organization.ID, 0, ctx.Params("variablename")); err != nil {
		if errors.Is(err, util.ErrInvalidArgument) {
			ctx.Error(http.StatusBadRequest, "DeleteVariableByName", err)
		} else if errors.Is(err, util.ErrNotExist) {
			ctx.NotFound(err)
		} else {
			ctx.InternalServerError(err)
		}
		return
	}

	ctx.Status(http.StatusNoContent)
}

func CreateVariable(ctx *context.APIContext) {
	opt := web.GetForm(ctx).(*hat_api.CreateVariableOption)
	ownerID := ctx.Org.Organization.ID
	variableName := ctx.Params("variablename")

	v, err := hat_actions_service.GetVariable(ctx, hat_actions_model.FindVariablesOpts{
		OwnerID: ownerID,
		Name:    variableName,
	})
	if err != nil && !errors.Is(err, util.ErrNotExist) {
		ctx.InternalServerError(err)
		return
	}
	if v != nil && v.ID > 0 {
		ctx.Error(http.StatusConflict, "", util.NewAlreadyExistErrorf("variable name %s already exists", variableName))
		return
	}

	if _, err := hat_actions_service.CreateVariable(ctx, ownerID, 0, variableName, opt.Value); err != nil {
		if errors.Is(err, util.ErrInvalidArgument) {
			ctx.Error(http.StatusBadRequest, "CreateVariable", err)
		} else {
			ctx.InternalServerError(err)
		}
		return
	}

	ctx.Status(http.StatusCreated)
}

func UpdateVariable(ctx *context.APIContext) {
	opt := web.GetForm(ctx).(*hat_api.UpdateVariableOption)

	v, err := hat_actions_service.GetVariable(ctx, hat_actions_model.FindVariablesOpts{
		OwnerID: ctx.Org.Organization.ID,
		Name:    ctx.Params("variablename"),
	})
	if err != nil {
		if errors.Is(err, util.ErrNotExist) {
			ctx.Error(http.StatusNotFound, "GetVariable", err)
		} else {
			ctx.InternalServerError(err)
		}
		return
	}

	if opt.Name == "" {
		opt.Name = ctx.Params("variablename")
	}

	v.Name = opt.Name
	v.Data = opt.Value

	if _, err := hat_actions_service.UpdateVariableNameData(ctx, v); err != nil {
		if errors.Is(err, util.ErrInvalidArgument) {
			ctx.Error(http.StatusBadRequest, "UpdateVariableNameData", err)
		} else {
			ctx.InternalServerError(err)
		}
		return
	}

	ctx.Status(http.StatusNoContent)
}

func ListVariables(ctx *context.APIContext) {
	opts := hat_actions_model.FindVariablesOpts{
		OwnerID:     ctx.Org.Organization.ID,
		ListOptions: utils.GetListOptions(ctx),
	}

	vars, err := hat_actions_model.FindVariables(ctx, opts)

	if err != nil {
		ctx.InternalServerError(err)
		return
	}

	count, err := hat_actions_model.CountVariables(ctx, opts)

	if err != nil {
		ctx.InternalServerError(err)
		return
	}

	variables := make([]*hat_api.ActionVariable, len(vars))
	for i, v := range vars {
		variables[i] = &hat_api.ActionVariable{
			OwnerID: v.OwnerID,
			RepoID:  v.RepoID,
			Name:    v.Name,
			Data:    v.Data,
		}
	}

	ctx.SetTotalCountHeader(count)
	ctx.JSON(http.StatusOK, variables)
}
