package service

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
	"net"

	"git.zkcoi.com/zkcoi/meshray/internal/ctr"
	"git.zkcoi.com/zkcoi/meshray/internal/model"
	"git.zkcoi.com/zkcoi/meshray/internal/store/sqlite"
	"git.zkcoi.com/zkcoi/meshray/pkg/idutil"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

// NetworkService 网络管理服务
type NetworkService struct {
	store     *sqlite.Store
	ctrClient ctr.Client // meshray-ctr 客户端
	logger    *zap.Logger
}

// NewNetworkService 创建网络服务实例
func NewNetworkService(store *sqlite.Store, ctrClient ctr.Client, logger *zap.Logger) *NetworkService {
	return &NetworkService{
		store:     store,
		ctrClient: ctrClient,
		logger:    logger,
	}
}

// ListNetworks 获取网络列表（Service 层方法）
func (s *NetworkService) ListNetworks() ([]model.Network, error) {
	var networks []model.Network
	err := s.store.DB().Preload("Devices").Find(&networks).Error
	return networks, err
}

// GetNetworkByID 根据 ID 获取网络
func (s *NetworkService) GetNetworkByID(id uint64) (*model.Network, error) {
	var network model.Network
	err := s.store.DB().Preload("Devices").First(&network, id).Error
	if err != nil {
		return nil, err
	}
	return &network, nil
}

// CreateNetwork 创建网络
func (s *NetworkService) CreateNetwork(req *model.Network) (*model.Network, error) {
	// 验证子网格式
	if err := s.validateSubnet(req.SubnetIPv4); err != nil {
		return nil, err
	}

	// 检查网络名称是否重复
	var existing model.Network
	if err := s.store.DB().Where("name = ?", req.Name).First(&existing).Error; err == nil {
		return nil, errors.New("网络名称已存在")
	}

	// 生成雪花算法 ID
	if req.ID == 0 {
		gen, err := idutil.GetGenerator()
		if err != nil {
			return nil, fmt.Errorf("failed to get snowflake generator: %w", err)
		}
		req.ID, err = gen.NextID()
		if err != nil {
			return nil, fmt.Errorf("failed to generate network id: %w", err)
		}
	}

	// 计算 listenPort：51820 + hash(networkID)（先不保存，用于 ctr 调用）
	listenPort := 51820 + hashUint64(req.ID)%1000

	// 根据组网模式决定是否启动 Core
	// 原生模式：仅创建 WG 设备
	// 增强模式：创建 WG 设备 + 启动 Core 实例
	if s.ctrClient != nil {
		// P2 阶段 - 先调用 meshray-ctr 创建 WireGuard 设备（失败则不回滚数据库）
		// 策略：宽松模式 - ctr 失败只记录警告，不影响数据库操作
		if err := s.ctrClient.CreateNetwork(req.ID, req.SubnetIPv4, listenPort, req.Mode); err != nil {
			// 记录错误但不影响数据库操作（允许降级）
			s.logger.Warn("调用 ctr 创建网络失败，将手动启动",
				zap.Uint64("network_id", req.ID),
				zap.Error(err))
		}
	}

	// 保存到数据库
	if err := s.store.DB().Create(req).Error; err != nil {
		return nil, err
	}

	s.logger.Info("网络创建成功",
		zap.Uint64("network_id", req.ID),
		zap.String("mode", req.Mode))

	return req, nil
}

// GetNetwork 获取网络详情
func (s *NetworkService) GetNetwork(id uint64) (*model.Network, error) {
	var network model.Network
	if err := s.store.DB().First(&network, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("网络不存在")
		}
		return nil, err
	}
	return &network, nil
}

// UpdateNetwork 更新网络
func (s *NetworkService) UpdateNetwork(id uint64, updates map[string]interface{}) (*model.Network, error) {
	var network model.Network
	if err := s.store.DB().First(&network, id).Error; err != nil {
		return nil, errors.New("网络不存在")
	}

	if err := s.store.DB().Model(&network).Updates(updates).Error; err != nil {
		return nil, err
	}

	return &network, nil
}

// DeleteNetwork 删除网络
func (s *NetworkService) DeleteNetwork(id uint64, force bool) error {
	// ✅ 使用事务保证数据一致性
	tx := s.store.DB().Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	var network model.Network
	if err := tx.First(&network, id).Error; err != nil {
		tx.Rollback()
		return errors.New("网络不存在")
	}

	// 检查是否有关联的设备
	var deviceCount int64
	tx.Model(&model.Device{}).Where("network_id = ?", id).Count(&deviceCount)
	if deviceCount > 0 {
		if !force {
			tx.Rollback()
			return errors.New("该网络下仍有设备，为避免误操作，请确认后强制删除")
		}
		// 级联删除所有关联设备
		if err := tx.Where("network_id = ?", id).Delete(&model.Device{}).Error; err != nil {
			tx.Rollback()
			return fmt.Errorf("级联删除设备失败：%w", err)
		}
		s.logger.Info("级联删除了关联设备", zap.Uint64("network_id", id), zap.Int64("device_count", deviceCount))
	}

	// 先调用 ctr 删除 WG 设备（如果存在）
	if s.ctrClient != nil {
		if err := s.ctrClient.DeleteNetwork(id); err != nil {
			// 记录错误但不中断删除流程（设备可能已经不存在）
			s.logger.Warn("删除 WG 设备失败（可能已不存在）",
				zap.Uint64("network_id", id),
				zap.Error(err))
			// 继续删除数据库记录
		}
	}

	// 再删除数据库记录
	if err := tx.Delete(&network, id).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 提交事务
	if err := tx.Commit().Error; err != nil {
		return err
	}

	return nil
}

// validateSubnet 验证子网格式
func (s *NetworkService) validateSubnet(subnet string) error {
	// 只调用一次 ParseCIDR
	ip, ipNet, err := net.ParseCIDR(subnet)
	if err != nil {
		return fmt.Errorf("无效的子网格式：%s", subnet)
	}

	// 检查是否是有效的 WireGuard 子网（至少 /24 或更小）
	ones, bits := ipNet.Mask.Size()

	if bits == 32 && ones > 24 {
		return errors.New("IPv4 子网掩码不能大于 /24")
	}
	if bits == 128 && ones > 64 {
		return errors.New("IPv6 子网掩码不能大于 /64")
	}

	// 检查是否是私有地址段
	if !isPrivateSubnet(ip, ipNet) {
		return errors.New("请使用私有地址段（如 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16）")
	}

	return nil
}

// isPrivateSubnet 检查是否是私有地址段
func isPrivateSubnet(ip net.IP, ipNet *net.IPNet) bool {
	// IPv4 私有地址段
	privateRanges := []string{
		"10.0.0.0/8",
		"172.16.0.0/12",
		"192.168.0.0/16",
		"100.64.0.0/10", // CGNAT
	}

	for _, privRange := range privateRanges {
		_, privNet, _ := net.ParseCIDR(privRange)
		if privNet.Contains(ip) {
			return true
		}
	}

	return false
}

// generateNetworkSecret 生成 Network Secret
func generateNetworkSecret() string {
	// 使用加密安全的随机数生成器
	bytes := make([]byte, 32)
	if _, err := rand.Read(bytes); err != nil {
		// ✅ 随机数生成失败时 panic，而不是返回弱密码
		panic(fmt.Sprintf("生成安全随机数失败：%v", err))
	}
	return hex.EncodeToString(bytes)
}

// hashUint64 计算 uint64 哈希值
func hashUint64(id uint64) int {
	h := sha256.Sum256([]byte(fmt.Sprintf("%d", id)))
	// 取前 4 字节转换为 int
	return int(h[0])<<24 | int(h[1])<<16 | int(h[2])<<8 | int(h[3])
}

// StartNetwork 启动网络
func (s *NetworkService) StartNetwork(id uint64) error {
	network, err := s.GetNetworkByID(id)
	if err != nil {
		return err
	}

	// 如果已经有 ctr，直接调用 CreateNetwork
	if s.ctrClient != nil {
		listenPort := 51820 + hashUint64(network.ID)%1000
		if err := s.ctrClient.CreateNetwork(network.ID, network.SubnetIPv4, listenPort, network.Mode); err != nil {
			s.logger.Error("启动网络失败",
				zap.Uint64("network_id", network.ID),
				zap.Error(err))
			return fmt.Errorf("启动网络失败：%w", err)
		}

		s.logger.Info("网络已启动",
			zap.Uint64("network_id", network.ID),
			zap.Int("listen_port", listenPort))
	}

	return nil
}

// StopNetwork 停止网络
func (s *NetworkService) StopNetwork(id uint64) error {
	network, err := s.GetNetworkByID(id)
	if err != nil {
		return err
	}

	// 调用 ctr 删除网络（清理 WG 设备）
	if s.ctrClient != nil {
		if err := s.ctrClient.DeleteNetwork(network.ID); err != nil {
			s.logger.Error("停止网络失败",
				zap.Uint64("network_id", network.ID),
				zap.Error(err))
			return fmt.Errorf("停止网络失败：%w", err)
		}

		s.logger.Info("网络已停止",
			zap.Uint64("network_id", network.ID))
	}

	return nil
}

// SwitchMode 切换组网模式
func (s *NetworkService) SwitchMode(id uint64, meshMode string) error {
	network, err := s.GetNetworkByID(id)
	if err != nil {
		return err
	}

	// 更新数据库
	if err := s.store.DB().Model(network).Update("mode", meshMode).Error; err != nil {
		return err
	}

	s.logger.Info("组网模式已切换",
		zap.Uint64("network_id", network.ID),
		zap.String("mode", meshMode))

	return nil
}
