package sign

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"fmt"
	"log"
	"net/url"
	"strconv"
	"time"

	"sms-receiver-go/config"
)

// GenerateSign 生成签名
func GenerateSign(timestamp int64, secret string) (string, error) {
	if secret == "" {
		return "", fmt.Errorf("secret 不能为空")
	}

	stringToSign := strconv.FormatInt(timestamp, 10) + "\n" + secret

	hmacCode := hmac.New(sha256.New, []byte(secret))
	hmacCode.Write([]byte(stringToSign))
	signBytes := hmacCode.Sum(nil)

	// Base64 编码
	signBase64 := base64.StdEncoding.EncodeToString(signBytes)

	// URL 编码
	sign := url.QueryEscape(signBase64)

	return sign, nil
}

// SignVerificationResult 签名验证结果
type SignVerificationResult struct {
	Valid      bool
	Reason     string
	TokenName  string
	Timestamp  int64
	ServerTime int64
}

// VerifySign 验证签名
func VerifySign(token string, timestamp int64, sign string, cfg *config.SecurityConfig) (*SignVerificationResult, error) {
	serverTime := time.Now().UnixMilli()

	// 如果未启用签名验证或未提供 token，直接通过
	if !cfg.SignVerify {
		return &SignVerificationResult{
			Valid:      true,
			Reason:     "签名验证未启用",
			Timestamp:  timestamp,
			ServerTime: serverTime,
		}, nil
	}

	if token == "" {
		return &SignVerificationResult{
			Valid:      false,
			Reason:     "未提供 token",
			Timestamp:  timestamp,
			ServerTime: serverTime,
		}, nil
	}

	// 查找对应的 token 配置
	tokenConfig := config.Get().GetTokenByValue(token)
	if tokenConfig == nil {
		return &SignVerificationResult{
			Valid:      false,
			Reason:     "无效的 token",
			Timestamp:  timestamp,
			ServerTime: serverTime,
		}, nil
	}

	secret := tokenConfig.Secret

	// 如果 secret 为空，则该 token 不要求签名验证
	if secret == "" {
		return &SignVerificationResult{
			Valid:      true,
			Reason:     "token 未配置 secret，跳过签名验证",
			TokenName:  tokenConfig.Name,
			Timestamp:  timestamp,
			ServerTime: serverTime,
		}, nil
	}

	// 检查时间戳是否过期
	maxAge := int64(cfg.SignMaxAge)
	if maxAge == 0 {
		maxAge = 5 * 60 * 1000 // 默认5分钟
	}
	timeDiff := serverTime - timestamp
	if timeDiff > maxAge {
		log.Printf("签名验证失败: 时间戳过期 - token=%s, timestamp=%d, time_diff=%dms, max_age=%dms",
			token, timestamp, timeDiff, maxAge)
		return &SignVerificationResult{
			Valid:      false,
			Reason:     fmt.Sprintf("时间戳过期（差异: %.1f 秒）", float64(timeDiff)/1000),
			TokenName:  tokenConfig.Name,
			Timestamp:  timestamp,
			ServerTime: serverTime,
		}, nil
	}

	// 重新生成签名进行比较
	expectedSign, err := GenerateSign(timestamp, secret)
	if err != nil {
		return nil, fmt.Errorf("生成签名失败: %w", err)
	}

	// 比较签名
	if sign != expectedSign {
		log.Printf("签名验证失败: 签名不匹配 - token=%s, timestamp=%d, ip=unknown",
			token, timestamp)
		return &SignVerificationResult{
			Valid:      false,
			Reason:     "签名不匹配",
			TokenName:  tokenConfig.Name,
			Timestamp:  timestamp,
			ServerTime: serverTime,
		}, nil
	}

	// 签名验证通过
	log.Printf("签名验证成功: token=%s, timestamp=%d", token, timestamp)
	return &SignVerificationResult{
		Valid:      true,
		Reason:     "签名验证通过",
		TokenName:  tokenConfig.Name,
		Timestamp:  timestamp,
		ServerTime: serverTime,
	}, nil
}
