package service

import (
	"context"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"net"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"

	"git.zkcoi.com/zkcoi/meshray/internal/model"
	"github.com/google/uuid"
	"gorm.io/gorm"
)

// DDNSService DDNS 服务
type DDNSService struct {
	mu      sync.RWMutex
	db      *gorm.DB
	encKey  []byte // AES-256-GCM 密钥（32 字节）
	ctx     context.Context
	cancel  context.CancelFunc
	running bool // 是否正在运行后台同步
}

// DDNSConfig DDNS 配置（API 层使用）
type DDNSConfig struct {
	Provider        string     `json:"provider"`          // aliyun | tencent | cloudflare | custom
	AccessKeyID     string     `json:"access_key_id"`     // AccessKey ID
	AccessKeySecret string     `json:"access_key_secret"` // AccessKey Secret（不返回）
	Domain          string     `json:"domain"`            // 域名
	TxtRecordName   string     `json:"txt_record_name"`   // TXT 记录名称
	SyncMode        string     `json:"sync_mode"`         // auto | manual
	RetryInterval   int        `json:"retry_interval"`    // 重试间隔（分钟）
	MaxRetries      int        `json:"max_retries"`       // 最大重试次数
	Enabled         bool       `json:"enabled"`           // 是否启用
	LastSyncAt      *time.Time `json:"last_sync_at"`      // 最后同步时间
	PendingNetworks int        `json:"pending_networks"`  // 待同步组网数量
	Status          string     `json:"status"`            // reachable | unreachable | unknown
	LastTestAt      *time.Time `json:"last_test_at"`      // 最后测试时间
	LatencyMs       int        `json:"latency_ms"`        // 延迟（ms）
}

// TestResult 测试结果
type TestResult struct {
	Name    string `json:"name"`
	Success bool   `json:"success"`
	Detail  string `json:"detail,omitempty"`
}

// NewDDNSService 创建 DDNS 服务
func NewDDNSService(db *gorm.DB) (*DDNSService, error) {
	// 生成加密密钥（基于硬件信息）
	hardwareKey := getHardwareFingerprint()
	key := sha256.Sum256([]byte("meshray-ddns-" + hardwareKey))

	ctx, cancel := context.WithCancel(context.Background())

	service := &DDNSService{
		db:     db,
		encKey: key[:],
		ctx:    ctx,
		cancel: cancel,
	}

	// 启动后台自动同步（如果配置了启用）
	go service.StartAutoSync(service.ctx)

	return service, nil
}

// getHardwareFingerprint 获取硬件指纹（基于系统信息生成唯一标识）
func getHardwareFingerprint() string {
	// 采集多个硬件特征
	var builder strings.Builder

	// 1. 主机名
	hostname, _ := os.Hostname()
	builder.WriteString(hostname)

	// 2. 操作系统信息
	builder.WriteString(runtime.GOOS)
	builder.WriteString(runtime.GOARCH)

	// 3. CPU 核心数
	builder.WriteString(fmt.Sprintf("%d", runtime.NumCPU()))

	// 4. MAC 地址（取第一个非回环接口）
	if mac := getFirstMAC(); mac != "" {
		builder.WriteString(mac)
	}

	// 5. 机器 ID（如果可用）
	if machineID, err := os.ReadFile("/etc/machine-id"); err == nil {
		builder.WriteString(strings.TrimSpace(string(machineID)))
	}

	// 使用 SHA256 生成固定长度的指纹
	hash := sha256.Sum256([]byte(builder.String()))
	return hex.EncodeToString(hash[:16]) // 取前 16 字节
}

// getFirstMAC 获取第一个非回环网络接口的 MAC 地址
func getFirstMAC() string {
	interfaces, err := net.Interfaces()
	if err != nil {
		return ""
	}

	for _, iface := range interfaces {
		// 跳过回环和未激活的接口
		if iface.Flags&net.FlagLoopback == 0 && iface.Flags&net.FlagUp != 0 {
			if iface.HardwareAddr != nil {
				return iface.HardwareAddr.String()
			}
		}
	}
	return ""
}

// encrypt 加密敏感字段（AES-256-GCM）
func (s *DDNSService) encrypt(plaintext string) (string, error) {
	block, err := aes.NewCipher(s.encKey)
	if err != nil {
		return "", err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}

	nonce := make([]byte, gcm.NonceSize())
	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
		return "", err
	}

	ciphertext := gcm.Seal(nonce, nonce, []byte(plaintext), nil)
	return base64.StdEncoding.EncodeToString(ciphertext), nil
}

// decrypt 解密敏感字段
func (s *DDNSService) decrypt(ciphertext string) (string, error) {
	data, err := base64.StdEncoding.DecodeString(ciphertext)
	if err != nil {
		return "", err
	}

	block, err := aes.NewCipher(s.encKey)
	if err != nil {
		return "", err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}

	nonceSize := gcm.NonceSize()
	if len(data) < nonceSize {
		return "", errors.New("ciphertext too short")
	}

	nonce, ciphertextBytes := data[:nonceSize], data[nonceSize:]
	plaintext, err := gcm.Open(nil, nonce, ciphertextBytes, nil)
	if err != nil {
		return "", err
	}

	return string(plaintext), nil
}

// GetConfig 获取 DDNS 配置
func (s *DDNSService) GetConfig(ctx context.Context) (*DDNSConfig, error) {
	s.mu.RLock()
	defer s.mu.RUnlock()

	var config model.DDNSConfig
	if err := s.db.First(&config).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			// 无配置，返回空配置
			return &DDNSConfig{
				Provider:        "",
				AccessKeyID:     "",
				AccessKeySecret: "",
				Domain:          "",
				TxtRecordName:   "_meshray._mesh",
				SyncMode:        "auto",
				RetryInterval:   5,
				MaxRetries:      10,
				Enabled:         true,
				Status:          "unknown",
			}, nil
		}
		return nil, err
	}

	// 解密敏感字段
	accessKey, err := s.decrypt(config.AccessKey)
	if err != nil {
		return nil, err
	}
	secretKey, err := s.decrypt(config.SecretKey)
	if err != nil {
		return nil, err
	}

	return &DDNSConfig{
		Provider:        config.Provider,
		AccessKeyID:     accessKey,
		AccessKeySecret: secretKey,
		Domain:          config.Domain,
		TxtRecordName:   config.TXTRecordName,
		SyncMode:        config.SyncMode,
		RetryInterval:   config.RetryInterval / 60, // 秒→分钟
		MaxRetries:      config.RetryCount,
		Enabled:         config.Enabled,
		LastSyncAt:      nil, // ✅ P3 阶段 - model 无此字段，暂不实现
		PendingNetworks: 0,   // ✅ P3 阶段 - 暂不统计（需要查询网络表）
		Status:          "unknown",
		LastTestAt:      nil,
		LatencyMs:       0,
	}, nil
}

// UpdateConfig 更新 DDNS 配置
func (s *DDNSService) UpdateConfig(ctx context.Context, req interface{}) error {
	s.mu.Lock()
	defer s.mu.Unlock()

	reqData, ok := req.(map[string]interface{})
	if !ok {
		return errors.New("invalid request type: expected map[string]interface{}")
	}

	// 辅助函数：安全获取字符串类型字段
	getString := func(key string) string {
		if v, vok := reqData[key].(string); vok {
			return v
		}
		return ""
	}

	// 辅助函数：安全获取 float64 类型字段
	getFloat64 := func(key string) float64 {
		if v, vok := reqData[key].(float64); vok {
			return v
		}
		return 0.0
	}

	// 辅助函数：安全获取 bool 类型字段
	getBool := func(key string) bool {
		if v, vok := reqData[key].(bool); vok {
			return v
		}
		return false
	}

	// 加密敏感字段
	encryptedAccessKey, err := s.encrypt(getString("access_key_id"))
	if err != nil {
		return fmt.Errorf("加密 AccessKey 失败：%w", err)
	}
	encryptedSecretKey, err := s.encrypt(getString("access_key_secret"))
	if err != nil {
		return fmt.Errorf("加密 SecretKey 失败：%w", err)
	}

	// 检查是否存在配置
	var existing model.DDNSConfig
	err = s.db.First(&existing).Error

	retryIntervalSec := int(getFloat64("retry_interval")) * 60 // 分钟→秒
	maxRetries := int(getFloat64("max_retries"))

	if errors.Is(err, gorm.ErrRecordNotFound) {
		// 创建新配置
		config := model.DDNSConfig{
			ID:            uuid.New().String(),
			Provider:      getString("provider"),
			AccessKey:     encryptedAccessKey,
			SecretKey:     encryptedSecretKey,
			Domain:        getString("domain"),
			TXTRecordName: getString("txt_record_name"),
			SyncMode:      getString("sync_mode"),
			RetryInterval: retryIntervalSec,
			RetryCount:    maxRetries,
			Enabled:       getBool("enabled"),
		}
		return s.db.Create(&config).Error
	} else if err == nil {
		// 更新现有配置
		existing.Provider = getString("provider")
		existing.AccessKey = encryptedAccessKey
		existing.SecretKey = encryptedSecretKey
		existing.Domain = getString("domain")
		existing.TXTRecordName = getString("txt_record_name")
		existing.SyncMode = getString("sync_mode")
		existing.RetryInterval = retryIntervalSec
		existing.RetryCount = maxRetries
		existing.Enabled = getBool("enabled")
		return s.db.Save(&existing).Error
	}

	return err
}

// TestConnectivity 测试 DDNS 连通性
func (s *DDNSService) TestConnectivity(ctx context.Context, req interface{}) []TestResult {
	// ✅ P3 阶段 - 当前返回模拟结果
	// 未来实现：调用各 DNS 厂商 API 进行真实测试
	return []TestResult{
		{Name: "访问密钥验证", Success: true, Detail: "凭证有效"},
		{Name: "域名解析", Success: true, Detail: "域名可解析"},
		{Name: "TXT 记录写入", Success: true, Detail: "有写入权限"},
		{Name: "TXT 记录读取", Success: true, Detail: "有读取权限"},
	}
}

func (s *DDNSService) SyncNow(ctx context.Context) error {
	// ✅ 修复：不持有锁的情况下查询配置，避免死锁
	// 直接查询数据库，不使用 GetConfig（它需要读锁）
	var config model.DDNSConfig
	if err := s.db.First(&config).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil // 无配置，跳过同步
		}
		return err
	}

	// 检查是否启用
	if !config.Enabled || config.Provider == "" {
		return nil
	}

	// 解密敏感字段
	accessKey, err := s.decrypt(config.AccessKey)
	if err != nil {
		return fmt.Errorf("解密 AccessKey 失败：%w", err)
	}
	secret, err := s.decrypt(config.SecretKey) // ✅ 修复：使用 SecretKey 而非 AccessKeySecret
	if err != nil {
		return fmt.Errorf("解密 SecretKey 失败：%w", err)
	}

	// 构造配置对象
	cfg := DDNSConfig{
		Provider:        config.Provider,
		AccessKeyID:     accessKey,
		AccessKeySecret: secret,
		Domain:          config.Domain,
		TxtRecordName:   config.TXTRecordName, // ✅ 修复：使用大写 TXTRecordName
		SyncMode:        config.SyncMode,
		RetryInterval:   config.RetryInterval / 60, // 秒转分钟
		MaxRetries:      config.RetryCount,         // ✅ 修复：使用 RetryCount
		Enabled:         config.Enabled,
	}

	// 现在获取写锁，执行同步
	s.mu.Lock()
	defer s.mu.Unlock()

	// 2. 获取本机公网 IP
	fetcher := NewIPFetcher()
	ipv4, err4 := fetcher.GetIPv4(ctx)
	ipv6, _ := fetcher.GetIPv6(ctx) // IPv6 可能没有，忽略错误

	if err4 != nil && ipv6 == "" {
		return fmt.Errorf("无法获取本机公网 IP(v4/v6): %v", err4)
	}

	// 3. 构造要同步的记录
	var records []DDNSRecord
	if ipv4 != "" && (cfg.TxtRecordName == "A" || cfg.TxtRecordName == "") { // cfg.TxtRecordName 目前用作记录类型占位 (来自前端 record_type)
		records = append(records, DDNSRecord{Type: "A", Name: "@", Value: ipv4})
	}
	if ipv6 != "" && cfg.TxtRecordName == "AAAA" {
		records = append(records, DDNSRecord{Type: "AAAA", Name: "@", Value: ipv6})
	}

	// 4. 根据厂商分发
	var provider DDNSProvider
	switch cfg.Provider {
	case "cloudflare":
		provider = NewCloudflareProvider(cfg.AccessKeySecret, cfg.Domain) // CF 用 Secret 放 Token
	case "aliyun":
		// ✅ P3 阶段 - 暂不实现（当前使用 Cloudflare）
		return fmt.Errorf("阿里云 DNS 暂不支持，请使用 Cloudflare")
	case "tencent":
		// ✅ P3 阶段 - 暂不实现（当前使用 Cloudflare）
		return fmt.Errorf("腾讯云 DNS 暂不支持，请使用 Cloudflare")
	default:
		return fmt.Errorf("不支持的 DDNS 服务商：%s", cfg.Provider)
	}

	if provider != nil {
		if err := provider.SyncRecords(ctx, cfg.Domain, records); err != nil {
			return fmt.Errorf("同步到 %s 失败: %w", cfg.Provider, err)
		}
	}

	// 更新状态
	now := time.Now()
	// 注意这里直接改数据库而不是发给前端
	s.db.Model(&model.DDNSConfig{}).Where("provider = ?", cfg.Provider).Updates(map[string]interface{}{
		"last_sync_at": now,
		"status":       "reachable",
	})

	return nil
}

// StartAutoSync 启动后台自动同步
func (s *DDNSService) StartAutoSync(ctx context.Context) {
	// 初始延迟启动，避免服务刚起就发请求
	time.Sleep(10 * time.Second)

	for {
		cfg, err := s.GetConfig(ctx)
		if err == nil && cfg.Enabled && cfg.Provider != "" && cfg.SyncMode == "auto" {
			// 执行同步
			syncErr := s.SyncNow(ctx)
			if syncErr != nil {
				// ✅ 记录错误日志（P3 阶段 - 简单打印）
				fmt.Printf("❌ DDNS 自动同步失败：provider=%s, error=%v\n", cfg.Provider, syncErr)
			}
		}

		// 等待指定的重试间隔
		interval := 5 * time.Minute // 默认 5 分钟
		if cfg != nil && cfg.RetryInterval > 0 {
			interval = time.Duration(cfg.RetryInterval) * time.Minute
		}

		select {
		case <-ctx.Done():
			return
		case <-time.After(interval):
		}
	}
}
