// Package role 提供角色默认信用模板的应用用例。
package role

import (
	"context"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
	"gorm.io/gorm"
)

// PermissionChecker 检查平台账号是否拥有独立信用模板权限。
type PermissionChecker interface {
	CheckPermission(ctx context.Context, userID uint, permCode string, platform string) (bool, error)
}

// DefaultCreditService 更新客户角色的新建代理默认信用模板。
type DefaultCreditService struct {
	db                *gorm.DB
	permissionChecker PermissionChecker
}

// NewDefaultCreditService 创建角色默认信用模板服务。
func NewDefaultCreditService(db *gorm.DB, permissionChecker PermissionChecker) *DefaultCreditService {
	return &DefaultCreditService{db: db, permissionChecker: permissionChecker}
}

// Update 更新模板；该操作不扫描或修改任何既有钱包。
func (s *DefaultCreditService) Update(ctx context.Context, roleID uint, enabled bool, limit int64) (*model.Role, error) {
	operatorID := middleware.GetUserIDFromContext(ctx)
	if operatorID == 0 {
		return nil, errors.New(errors.CodeUnauthorized)
	}
	if err := s.authorize(ctx, operatorID); err != nil {
		return nil, err
	}
	if err := validateDefaultCredit(enabled, limit); err != nil {
		return nil, err
	}

	var role model.Role
	err := s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		if err := tx.Clauses().First(&role, roleID).Error; err != nil {
			if err == gorm.ErrRecordNotFound {
				return errors.New(errors.CodeRoleNotFound)
			}
			return errors.Wrap(errors.CodeInternalError, err, "读取角色失败")
		}
		if role.RoleType != constants.RoleTypeCustomer {
			return errors.New(errors.CodeInvalidParam, "只有客户角色可以配置新建代理默认信用")
		}

		result := tx.Model(&model.Role{}).
			Where("id = ? AND role_type = ?", roleID, constants.RoleTypeCustomer).
			Updates(map[string]any{
				"default_credit_enabled": enabled,
				"default_credit_limit":   limit,
				"updater":                operatorID,
			})
		if result.Error != nil {
			return errors.Wrap(errors.CodeInternalError, result.Error, "更新角色默认信用失败")
		}
		if result.RowsAffected != 1 {
			return errors.New(errors.CodeConflict, "角色默认信用已发生变化，请刷新后重试")
		}
		role.DefaultCreditEnabled = enabled
		role.DefaultCreditLimit = limit
		role.Updater = operatorID
		return nil
	})
	if err != nil {
		return nil, err
	}
	return &role, nil
}

func (s *DefaultCreditService) authorize(ctx context.Context, operatorID uint) error {
	userType := middleware.GetUserTypeFromContext(ctx)
	if userType == constants.UserTypeSuperAdmin {
		return nil
	}
	if userType != constants.UserTypePlatform || s.permissionChecker == nil {
		return errors.New(errors.CodeForbidden, "无权限配置角色默认信用")
	}
	hasPermission, err := s.permissionChecker.CheckPermission(ctx, operatorID, constants.PermissionRoleDefaultCreditManage, constants.PlatformWeb)
	if err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "检查角色默认信用权限失败")
	}
	if !hasPermission {
		return errors.New(errors.CodeForbidden, "无权限配置角色默认信用")
	}
	return nil
}

func validateDefaultCredit(enabled bool, limit int64) error {
	if limit < 0 {
		return errors.New(errors.CodeInvalidParam, "默认信用额度不能为负数")
	}
	if enabled && limit == 0 {
		return errors.New(errors.CodeInvalidParam, "启用默认信用时额度必须大于零")
	}
	if !enabled && limit != 0 {
		return errors.New(errors.CodeInvalidParam, "关闭默认信用时额度必须为零")
	}
	return nil
}
