package sign_in_reward_rules

import (
	"context"
	"server/internal/dao"
	"server/internal/model"
	"server/internal/model/do"
	"server/internal/service"
	"server/utility/ecode"

	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/os/gtime"
)

type sSignInRewardRules struct{}

func New() service.ISignInRewardRules {
	return &sSignInRewardRules{}
}

func init() {
	service.RegisterSignInRewardRules(New())
}

// List 获取签到奖励规则列表
func (s *sSignInRewardRules) List(ctx context.Context, in *model.SignInRewardRulesListIn) (out *model.SignInRewardRulesListOut, err error) {
	out = &model.SignInRewardRulesListOut{}
	m := dao.SignInRewardRules.Ctx(ctx)
	if in.Status != 0 {
		m = m.Where(dao.SignInRewardRules.Columns().Status, in.Status)
	}
	if in.RuleName != "" {
		m = m.WhereLike(dao.SignInRewardRules.Columns().RuleName, "%"+in.RuleName+"%")
	}
	m = m.OrderDesc(dao.SignInRewardRules.Columns().CreatedAt)
	if err = m.Page(in.Page, in.Size).WithAll().ScanAndCount(&out.List, &out.Total, false); err != nil {
		return nil, ecode.Fail.Sub("sign_in_reward_rule_query_failed")
	}
	return out, nil
}

// Create 新增签到奖励规则
func (s *sSignInRewardRules) Create(ctx context.Context, in *model.SignInRewardRulesCreateIn) (out *model.SignInRewardRulesCRUDOut, err error) {
	// 检查同名未删除规则是否已存在
	exist, err := dao.SignInRewardRules.Ctx(ctx).
		Where(dao.SignInRewardRules.Columns().RuleName, in.RuleName).
		WhereNull(dao.SignInRewardRules.Columns().DeletedAt).
		Exist()
	if err != nil {
		return nil, ecode.Fail.Sub("sign_in_reward_rule_query_failed")
	}
	if exist {
		return nil, ecode.Params.Sub("sign_in_reward_rule_exists")
	}
	// 开启事务
	err = dao.SignInRewardRules.Ctx(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		result, err := dao.SignInRewardRules.Ctx(ctx).TX(tx).Data(do.SignInRewardRules{
			RuleName:  in.RuleName,
			CycleDays: in.CycleDays,
			StartDate: gtime.NewFromStr(in.StartDate),
			EndDate:   gtime.NewFromStr(in.EndDate),
			Status:    in.Status,
		}).InsertAndGetId()
		if err != nil {
			return ecode.Fail.Sub("sign_in_reward_rule_create_failed")
		}
		// 自动插入明细
		var details []do.SignInRewardDetails
		for i := 1; i <= in.CycleDays; i++ {
			details = append(details, do.SignInRewardDetails{
				RuleId:     result,
				DayNumber:  i,
				RewardType: 1, // 默认积分
				Quantity:   0,
				Status:     0, // 默认禁用
			})
		}
		if len(details) > 0 {
			_, err = dao.SignInRewardDetails.Ctx(ctx).TX(tx).Data(details).Insert()
			if err != nil {
				return ecode.Fail.Sub("sign_in_reward_rule_create_failed")
			}
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return &model.SignInRewardRulesCRUDOut{Success: true}, nil
}

// Update 编辑签到奖励规则
func (s *sSignInRewardRules) Update(ctx context.Context, in *model.SignInRewardRulesUpdateIn) (out *model.SignInRewardRulesCRUDOut, err error) {
	// 检查是否存在
	exist, err := dao.SignInRewardRules.Ctx(ctx).
		Where(dao.SignInRewardRules.Columns().Id, in.Id).
		WhereNull(dao.SignInRewardRules.Columns().DeletedAt).
		Exist()
	if err != nil {
		return nil, ecode.Fail.Sub("sign_in_reward_rule_query_failed")
	}
	if !exist {
		return nil, ecode.NotFound.Sub("sign_in_reward_rule_not_found")
	}
	// 检查同名未删除规则是否有重复（排除自己）
	repeat, err := dao.SignInRewardRules.Ctx(ctx).
		Where(dao.SignInRewardRules.Columns().RuleName, in.RuleName).
		WhereNull(dao.SignInRewardRules.Columns().DeletedAt).
		WhereNot(dao.SignInRewardRules.Columns().Id, in.Id).
		Exist()
	if err != nil {
		return nil, ecode.Fail.Sub("sign_in_reward_rule_query_failed")
	}
	if repeat {
		return nil, ecode.Params.Sub("sign_in_reward_rule_exists")
	}
	_, err = dao.SignInRewardRules.Ctx(ctx).
		Where(dao.SignInRewardRules.Columns().Id, in.Id).
		Data(do.SignInRewardRules{
			RuleName:  in.RuleName,
			CycleDays: in.CycleDays,
			StartDate: gtime.NewFromStr(in.StartDate),
			EndDate:   gtime.NewFromStr(in.EndDate),
			Status:    in.Status,
		}).Update()
	if err != nil {
		return nil, ecode.Fail.Sub("sign_in_reward_rule_update_failed")
	}
	return &model.SignInRewardRulesCRUDOut{Success: true}, nil
}

// Delete 删除签到奖励规则
func (s *sSignInRewardRules) Delete(ctx context.Context, in *model.SignInRewardRulesDeleteIn) (out *model.SignInRewardRulesCRUDOut, err error) {
	// 检查是否存在
	exist, err := dao.SignInRewardRules.Ctx(ctx).
		Where(dao.SignInRewardRules.Columns().Id, in.Id).
		WhereNull(dao.SignInRewardRules.Columns().DeletedAt).
		Exist()
	if err != nil {
		return nil, ecode.Fail.Sub("sign_in_reward_rule_query_failed")
	}
	if !exist {
		return nil, ecode.NotFound.Sub("sign_in_reward_rule_not_found")
	}
	_, err = dao.SignInRewardRules.Ctx(ctx).
		Where(dao.SignInRewardRules.Columns().Id, in.Id).
		Delete()
	if err != nil {
		return nil, ecode.Fail.Sub("sign_in_reward_rule_delete_failed")
	}
	return &model.SignInRewardRulesCRUDOut{Success: true}, nil
}

// SetStatus 设置签到奖励规则状态
func (s *sSignInRewardRules) SetStatus(ctx context.Context, in *model.SignInRewardRulesSetStatusIn) (out *model.SignInRewardRulesCRUDOut, err error) {
	// 检查是否存在
	exist, err := dao.SignInRewardRules.Ctx(ctx).
		Where(dao.SignInRewardRules.Columns().Id, in.Id).
		WhereNull(dao.SignInRewardRules.Columns().DeletedAt).
		Exist()
	if err != nil {
		return nil, ecode.Fail.Sub("sign_in_reward_rule_query_failed")
	}
	if !exist {
		return nil, ecode.NotFound.Sub("sign_in_reward_rule_not_found")
	}
	_, err = dao.SignInRewardRules.Ctx(ctx).
		Where(dao.SignInRewardRules.Columns().Id, in.Id).
		Data(do.SignInRewardRules{
			Status: in.Status,
		}).Update()
	if err != nil {
		return nil, ecode.Fail.Sub("sign_in_reward_rule_update_failed")
	}
	return &model.SignInRewardRulesCRUDOut{Success: true}, nil
}

func (s *sSignInRewardRules) SignInList(ctx context.Context, in *model.SignInListIn) (out *model.SignInListOut, err error) {
	// 查询活动（只取一条）
	out = &model.SignInListOut{}
	err = dao.SignInRewardRules.Ctx(ctx).Where(do.SignInRewardRules{Status: 1}).OrderDesc("created_at").WithAll().Limit(1).Scan(&out)
	if err != nil {
		return nil, err
	}

	// 查询用户在该活动下的签到记录
	if in.UserId == 0 {
		return
	}
	userSignLogs, err := dao.UserSignInLogs.Ctx(ctx).Where(do.UserSignInLogs{UserId: in.UserId, RuleId: out.Id}).Fields(dao.UserSignInLogs.Columns().RewardDetailId).Array()
	if err != nil {
		return nil, err
	}
	claimedMap := make(map[int64]bool, 0)
	for _, log := range userSignLogs {
		claimedMap[log.Int64()] = true
	}

	// 填充 IsClaimed
	for i := range out.List {
		if claimedMap[out.List[i].Id] {
			out.List[i].IsClaimed = true
		}
	}

	return out, nil
}
