package postgres

import (
	"context"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/redis/go-redis/v9"
	"gorm.io/gorm"
)

// RolePermissionStore 角色-权限关联数据访问层
type RolePermissionStore struct {
	db          *gorm.DB
	redisClient *redis.Client
}

// NewRolePermissionStore 创建角色-权限关联 Store
func NewRolePermissionStore(db *gorm.DB, redisClient *redis.Client) *RolePermissionStore {
	return &RolePermissionStore{
		db:          db,
		redisClient: redisClient,
	}
}

// Create 创建角色-权限关联，唯一约束冲突时幂等处理
func (s *RolePermissionStore) Create(ctx context.Context, rp *model.RolePermission) error {
	if err := s.db.WithContext(ctx).Create(rp).Error; err != nil {
		// 并发竞态导致唯一约束冲突，视为已存在，幂等返回
		if isUniqueViolation(err) {
			return nil
		}
		return err
	}
	s.clearRoleUsersCaches(ctx, rp.RoleID)
	return nil
}

// BatchCreate 批量创建角色-权限关联
func (s *RolePermissionStore) BatchCreate(ctx context.Context, rps []*model.RolePermission) error {
	if err := s.db.WithContext(ctx).Create(&rps).Error; err != nil {
		return err
	}
	roleIDs := make(map[uint]bool)
	for _, rp := range rps {
		roleIDs[rp.RoleID] = true
	}
	for roleID := range roleIDs {
		s.clearRoleUsersCaches(ctx, roleID)
	}
	return nil
}

// Delete 软删除角色-权限关联
func (s *RolePermissionStore) Delete(ctx context.Context, roleID, permID uint) error {
	if err := s.db.WithContext(ctx).
		Where("role_id = ? AND perm_id = ?", roleID, permID).
		Delete(&model.RolePermission{}).Error; err != nil {
		return err
	}
	s.clearRoleUsersCaches(ctx, roleID)
	return nil
}

// BatchDelete 批量软删除角色-权限关联
func (s *RolePermissionStore) BatchDelete(ctx context.Context, roleID uint, permIDs []uint) error {
	if err := s.db.WithContext(ctx).
		Where("role_id = ? AND perm_id IN ?", roleID, permIDs).
		Delete(&model.RolePermission{}).Error; err != nil {
		return err
	}
	s.clearRoleUsersCaches(ctx, roleID)
	return nil
}

// DeleteByRoleID 删除角色的所有权限关联
func (s *RolePermissionStore) DeleteByRoleID(ctx context.Context, roleID uint) error {
	if err := s.db.WithContext(ctx).
		Where("role_id = ?", roleID).
		Delete(&model.RolePermission{}).Error; err != nil {
		return err
	}
	s.clearRoleUsersCaches(ctx, roleID)
	return nil
}

func (s *RolePermissionStore) clearRoleUsersCaches(ctx context.Context, roleID uint) {
	if s.redisClient == nil {
		return
	}

	var accountIDs []uint
	if err := s.db.WithContext(ctx).
		Model(&model.AccountRole{}).
		Where("role_id = ?", roleID).
		Pluck("account_id", &accountIDs).Error; err != nil {
		return
	}

	for _, accountID := range accountIDs {
		key := constants.RedisUserPermissionsKey(accountID)
		s.redisClient.Del(ctx, key)
	}
}

// GetByRoleID 获取角色的所有权限关联
func (s *RolePermissionStore) GetByRoleID(ctx context.Context, roleID uint) ([]*model.RolePermission, error) {
	var rps []*model.RolePermission
	if err := s.db.WithContext(ctx).
		Where("role_id = ?", roleID).
		Find(&rps).Error; err != nil {
		return nil, err
	}
	return rps, nil
}

// GetPermIDsByRoleID 获取角色的所有权限 ID
func (s *RolePermissionStore) GetPermIDsByRoleID(ctx context.Context, roleID uint) ([]uint, error) {
	var permIDs []uint
	if err := s.db.WithContext(ctx).
		Model(&model.RolePermission{}).
		Where("role_id = ?", roleID).
		Pluck("perm_id", &permIDs).Error; err != nil {
		return nil, err
	}
	return permIDs, nil
}

// GetPermIDsByRoleIDs 获取多个角色的所有权限 ID
func (s *RolePermissionStore) GetPermIDsByRoleIDs(ctx context.Context, roleIDs []uint) ([]uint, error) {
	var permIDs []uint
	if err := s.db.WithContext(ctx).
		Model(&model.RolePermission{}).
		Where("role_id IN ?", roleIDs).
		Distinct().
		Pluck("perm_id", &permIDs).Error; err != nil {
		return nil, err
	}
	return permIDs, nil
}

// Exists 检查角色-权限关联是否存在
func (s *RolePermissionStore) Exists(ctx context.Context, roleID, permID uint) (bool, error) {
	var count int64
	if err := s.db.WithContext(ctx).
		Model(&model.RolePermission{}).
		Where("role_id = ? AND perm_id = ?", roleID, permID).
		Count(&count).Error; err != nil {
		return false, err
	}
	return count > 0, nil
}
