package point

import (
	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/base"
	"code.gitea.io/gitea/modules/context"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/routers/response"
	"code.gitea.io/gitea/services/reward"
	"code.gitea.io/gitea/services/reward/point/account"
	"code.gitea.io/gitea/services/task"
	"errors"
	"net/http"
)

const tplPoint base.TplName = "reward/point"
const tplPointRule base.TplName = "reward/point/rule"

type AccountResponse struct {
	Balance       int64
	TotalEarned   int64
	TotalConsumed int64
}

func GetPointAccount(ctx *context.Context) {
	userId := ctx.User.ID
	a, err := account.GetAccount(userId)
	if err != nil {
		ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
		return
	}
	res := &AccountResponse{
		Balance:       a.Balance,
		TotalEarned:   a.TotalEarned,
		TotalConsumed: a.TotalConsumed,
	}
	ctx.JSON(http.StatusOK, response.SuccessWithData(res))
}

func GetPointRecordList(ctx *context.Context) {
	operateType := ctx.Query("Operate")
	page := ctx.QueryInt("Page")
	var orderBy models.RewardOperateOrderBy
	switch ctx.Query("sort") {
	default:
		orderBy = models.RewardOrderByIDDesc
	}
	t := models.GetRewardOperateTypeInstance(operateType)
	if t == "" {
		ctx.JSON(http.StatusOK, response.ServerError("param error"))
		return
	}

	r, err := reward.GetRewardRecordList(&models.RewardRecordListOpts{
		ListOptions: models.ListOptions{PageSize: 10, Page: page},
		UserId:      ctx.User.ID,
		OperateType: t,
		RewardType:  models.RewardTypePoint,
		OrderBy:     orderBy,
		IsAdmin:     false,
		UserName:    ctx.User.Name,
	})
	if err != nil {
		log.Error("GetPointRecordList error.%v", err)
		ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
		return
	}

	ctx.JSON(http.StatusOK, response.SuccessWithData(r))
	return
}

func OperatePointAccountBalance(ctx *context.Context, req models.AdminRewardOperateReq) {
	req.RewardType = models.RewardTypePoint
	if req.OperateType.Name() == "" || req.Remark == "" {
		ctx.JSON(http.StatusOK, "param error")
		return
	}
	err := reward.AdminBalanceOperate(req, ctx.User)
	if err != nil {
		log.Error("OperatePointAccountBalance error.%v", err)
		ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
		return
	}
	ctx.JSON(http.StatusOK, response.Success())
}

func GetPointPage(ctx *context.Context) {
	ctx.HTML(200, tplPoint)
}

func GetRulePage(ctx *context.Context) {
	ctx.HTML(200, tplPointRule)
}

func GetRuleConfig(ctx *context.Context) {
	r, err := task.GetPointRule()
	if err != nil {
		log.Error("GetRuleConfig error.%v", err)
		ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
		return
	}

	ctx.JSON(http.StatusOK, response.SuccessWithData(r))
}

func GetAdminRewardList(ctx *context.Context) {
	opts, err := buildAdminRewardRecordListOpts(ctx)
	if err != nil {
		log.Error("buildAdminRewardRecordListOpts error.%v", err)
		ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
		return
	}

	username := ctx.Query("userName")
	if username != "" {
		user, err := models.GetUserByName(username)
		if err != nil {
			log.Error("GetUserByName error.%v", err)
			if models.IsErrUserNotExist(err) {
				ctx.JSON(http.StatusOK, response.ServerError("user not exist"))
			} else {
				ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
			}
			return
		}
		opts.UserId = user.ID
		opts.UserName = user.Name
	}

	r, err := reward.GetRewardRecordList(opts)
	if err != nil {
		log.Error("GetRewardRecordList error.%v", err)
		ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
		return
	}

	ctx.JSON(http.StatusOK, response.SuccessWithData(r))
}

func buildAdminRewardRecordListOpts(ctx *context.Context) (*models.RewardRecordListOpts, error) {
	operateType := ctx.Query("operate")
	sourceType := ctx.Query("source")
	taskType := ctx.Query("action")
	serialNo := ctx.Query("serialNo")
	status := ctx.Query("status")

	page := ctx.QueryInt("page")
	var orderBy models.RewardOperateOrderBy
	switch ctx.Query("sort") {
	default:
		orderBy = models.RewardOrderByIDDesc
	}
	t := models.GetRewardOperateTypeInstance(operateType)
	if t == "" {
		return nil, errors.New("param error")
	}
	opts := &models.RewardRecordListOpts{
		ListOptions: models.ListOptions{PageSize: 10, Page: page},
		OperateType: t,
		RewardType:  models.RewardTypePoint,
		OrderBy:     orderBy,
		SourceType:  sourceType,
		TaskType:    taskType,
		SerialNo:    serialNo,
		IsAdmin:     true,
		Status:      status,
	}
	return opts, nil
}
