package service

import (
	"crypto/rand"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"time"

	"git.zkcoi.com/zkcoi/meshray/internal/model"
	sqlite "git.zkcoi.com/zkcoi/meshray/internal/store/sqlite"
	"go.uber.org/zap"
	"golang.org/x/crypto/ed25519"
	"gorm.io/gorm"
)

// MeshSeedService MeshSeed 服务
type MeshSeedService struct {
	store        *sqlite.Store
	logger       *zap.Logger
	signingKey   ed25519.PrivateKey // Ed25519 签名密钥
	issuerNodeID string             // 签发节点 ID
}

// NewMeshSeedService 创建 MeshSeed 服务
func NewMeshSeedService(store *sqlite.Store, logger *zap.Logger, signingKey ed25519.PrivateKey, issuerNodeID string) *MeshSeedService {
	return &MeshSeedService{
		store:        store,
		logger:       logger,
		signingKey:   signingKey,
		issuerNodeID: issuerNodeID,
	}
}

// GenerateMeshSeed 生成 MeshSeed
func (s *MeshSeedService) GenerateMeshSeed(networkID uint64, maxUses int, expiresAt time.Time, ddnsEnabled bool) (*model.MeshSeed, error) {
	// 1. 验证网络是否存在
	var network model.Network
	if err := s.store.DB().First(&network, networkID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, fmt.Errorf("网络不存在")
		}
		return nil, fmt.Errorf("查询网络失败：%w", err)
	}

	// 2. 生成随机 SeedID（16 字节随机数）
	seedBytes := make([]byte, 16)
	if _, err := rand.Read(seedBytes); err != nil {
		return nil, fmt.Errorf("生成随机数失败：%w", err)
	}
	seedID := base64.RawURLEncoding.EncodeToString(seedBytes)

	// 3. 构建 JoinToken（包含网络信息）
	joinTokenData := map[string]interface{}{
		"seed_id":      seedID,
		"network_id":   networkID,
		"network_name": network.Name,
		"subnet_ipv4":  network.SubnetIPv4,
		"mode":         network.Mode,
		"ddns_enabled": ddnsEnabled,
		"expires_at":   expiresAt.Unix(),
		"max_uses":     maxUses,
	}

	// 序列化为 JSON
	tokenJSON, err := json.Marshal(joinTokenData)
	if err != nil {
		return nil, fmt.Errorf("序列化 Token 失败：%w", err)
	}

	// Base64 编码
	joinToken := base64.StdEncoding.EncodeToString(tokenJSON)

	// 4. Ed25519 签名
	signature := ed25519.Sign(s.signingKey, []byte(joinToken))
	signatureStr := base64.StdEncoding.EncodeToString(signature)

	// 5. 创建 MeshSeed 记录
	meshSeed := &model.MeshSeed{
		SeedID:        seedID,
		NetworkID:     networkID,
		JoinToken:     joinToken,
		Signature:     signatureStr,
		IssuerNodeID:  s.issuerNodeID,
		MaxUses:       maxUses,
		UsedCount:     0,
		ExpiresAt:     expiresAt,
		DDNSEnabled:   ddnsEnabled,
		UpdateVersion: 0,
		Revoked:       false,
	}

	if err := s.store.DB().Create(meshSeed).Error; err != nil {
		return nil, fmt.Errorf("创建 MeshSeed 失败：%w", err)
	}

	s.logger.Info("MeshSeed 已生成",
		zap.String("seed_id", seedID),
		zap.Uint64("network_id", networkID),
		zap.Int("max_uses", maxUses),
		zap.Time("expires_at", expiresAt))

	return meshSeed, nil
}

// VerifyMeshSeed 验证 MeshSeed
func (s *MeshSeedService) VerifyMeshSeed(joinToken, signature string) (*model.MeshSeed, error) {
	// 1. 解码 JoinToken
	tokenBytes, err := base64.StdEncoding.DecodeString(joinToken)
	if err != nil {
		return nil, fmt.Errorf("解码 Token 失败：%w", err)
	}

	// 2. 解码签名
	sigBytes, err := base64.StdEncoding.DecodeString(signature)
	if err != nil {
		return nil, fmt.Errorf("解码签名失败：%w", err)
	}

	// 3. 验证 Ed25519 签名
	publicKey := s.signingKey.Public()
	if !ed25519.Verify(publicKey.(ed25519.PublicKey), tokenBytes, sigBytes) {
		return nil, fmt.Errorf("签名验证失败")
	}

	// 4. 解析 Token 内容
	var tokenData map[string]interface{}
	if err := json.Unmarshal(tokenBytes, &tokenData); err != nil {
		return nil, fmt.Errorf("解析 Token 失败：%w", err)
	}

	seedID, ok := tokenData["seed_id"].(string)
	if !ok {
		return nil, fmt.Errorf("Token 格式错误")
	}

	// 5. 查询 MeshSeed
	var meshSeed model.MeshSeed
	if err := s.store.DB().Where("seed_id = ?", seedID).First(&meshSeed).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, fmt.Errorf("MeshSeed 不存在")
		}
		return nil, fmt.Errorf("查询 MeshSeed 失败：%w", err)
	}

	// 6. 检查是否被吊销
	if meshSeed.Revoked {
		return nil, fmt.Errorf("MeshSeed 已被吊销")
	}

	// 7. 检查使用次数
	if meshSeed.UsedCount >= meshSeed.MaxUses {
		return nil, fmt.Errorf("MeshSeed 使用次数已用尽")
	}

	// 8. 检查过期时间
	if time.Now().After(meshSeed.ExpiresAt) {
		return nil, fmt.Errorf("MeshSeed 已过期")
	}

	return &meshSeed, nil
}

// IncrementUseCount 增加使用次数
func (s *MeshSeedService) IncrementUseCount(seedID string) error {
	return s.store.DB().Transaction(func(tx *gorm.DB) error {
		var meshSeed model.MeshSeed
		if err := tx.Where("seed_id = ?", seedID).First(&meshSeed).Error; err != nil {
			return err
		}

		return tx.Model(&meshSeed).UpdateColumn("used_count", meshSeed.UsedCount+1).Error
	})
}

// RevokeMeshSeed 吊销 MeshSeed
func (s *MeshSeedService) RevokeMeshSeed(seedID string) error {
	result := s.store.DB().Model(&model.MeshSeed{}).
		Where("seed_id = ?", seedID).
		Update("revoked", true)

	if result.Error != nil {
		return fmt.Errorf("吊销 MeshSeed 失败：%w", result.Error)
	}

	if result.RowsAffected == 0 {
		return fmt.Errorf("MeshSeed 不存在")
	}

	s.logger.Info("MeshSeed 已吊销", zap.String("seed_id", seedID))
	return nil
}

// ListMeshSeeds 获取网络的 MeshSeed 列表
func (s *MeshSeedService) ListMeshSeeds(networkID uint) ([]model.MeshSeed, error) {
	var seeds []model.MeshSeed
	err := s.store.DB().Where("network_id = ? AND revoked = ?", networkID, false).
		Order("created_at DESC").
		Find(&seeds).Error

	return seeds, err
}
