// Package operation_password 提供全局操作密码的设置、查询与验证服务
// 操作密码以 bcrypt 哈希存储于 Redis，仅超级管理员可维护
package operation_password

import (
	"context"

	"github.com/redis/go-redis/v9"
	"golang.org/x/crypto/bcrypt"

	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
)

// Service 全局操作密码服务
type Service struct {
	redis *redis.Client
}

// New 创建操作密码服务实例
func New(rdb *redis.Client) *Service {
	return &Service{redis: rdb}
}

// Set 设置/修改全局操作密码
// 对明文密码做 bcrypt 哈希后永久存储到 Redis（无 TTL）
func (s *Service) Set(ctx context.Context, password string) error {
	hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "操作密码加密失败")
	}

	key := constants.RedisSystemOperationPasswordKey()
	if err := s.redis.Set(ctx, key, string(hash), 0).Err(); err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "操作密码存储失败")
	}

	return nil
}

// IsSet 查询操作密码是否已设置
func (s *Service) IsSet(ctx context.Context) bool {
	key := constants.RedisSystemOperationPasswordKey()
	n, err := s.redis.Exists(ctx, key).Result()
	if err != nil {
		return false
	}
	return n > 0
}

// Verify 验证操作密码是否正确
// key 不存在时返回"操作密码未设置"错误，密码错误时返回"操作密码错误"
func (s *Service) Verify(ctx context.Context, inputPassword string) error {
	key := constants.RedisSystemOperationPasswordKey()
	hash, err := s.redis.Get(ctx, key).Result()
	if err == redis.Nil {
		return errors.New(errors.CodeInvalidParam, "操作密码未设置，请联系超级管理员")
	}
	if err != nil {
		return errors.Wrap(errors.CodeInternalError, err, "查询操作密码失败")
	}

	if err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(inputPassword)); err != nil {
		return errors.New(errors.CodeInvalidParam, "操作密码错误")
	}

	return nil
}
