package service

import (
	"context"
	"fmt"
	"time"

	"git.zkcoi.com/zkcoi/meshray/internal/dnsprovider"
	"git.zkcoi.com/zkcoi/meshray/internal/model"
	"github.com/libdns/libdns"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

// DDNSOperationService DDNS 操作服务（全功能模式）
type DDNSOperationService struct {
	logger *zap.Logger
	db     *gorm.DB
}

// NewDDNSOperationService 创建 DDNS 操作服务
func NewDDNSOperationService(logger *zap.Logger, db *gorm.DB) *DDNSOperationService {
	return &DDNSOperationService{
		logger: logger,
		db:     db,
	}
}

// CreateDNSRecord 创建 DNS 记录（全功能模式）
func (s *DDNSOperationService) CreateDNSRecord(config *model.Service, recordType string, name string, value string, ttl int) error {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	// 1. 获取关联的 DDNS 配置
	ddnsConfig, err := s.getDDNSConfig(config.DDNSConfigID)
	if err != nil {
		return fmt.Errorf("获取 DDNS 配置失败：%w", err)
	}

	// 2. 创建 DNS Provider
	providerConfig := dnsprovider.ProviderConfig{
		Provider:        dnsprovider.ProviderType(ddnsConfig.Provider),
		Domain:          ddnsConfig.Domain,
		APIToken:        ddnsConfig.Token,
		AccessKeyID:     ddnsConfig.AuthUsername,
		AccessKeySecret: ddnsConfig.AuthPassword,
		SecretId:        ddnsConfig.AuthUsername,
		SecretKey:       ddnsConfig.AuthPassword,
	}

	provider, err := dnsprovider.NewDNSProvider(providerConfig)
	if err != nil {
		return fmt.Errorf("创建 DNS Provider 失败：%w", err)
	}

	// 3. 构建 DNS 记录
	dnsRecord := &dnsprovider.DNSRecord{
		Type:  dnsprovider.RecordType(recordType),
		Name:  name,
		Value: value,
		TTL:   ttl,
	}

	// 4. 添加 DNS 记录
	zone := ddnsConfig.Domain
	libdnsRecord := dnsRecord.ToLibdnsRecord()

	s.logger.Info("开始创建 DNS 记录",
		zap.String("type", recordType),
		zap.String("name", name),
		zap.String("value", value),
		zap.String("domain", zone))

	_, err = provider.AppendRecords(ctx, zone, []libdns.Record{libdnsRecord})
	if err != nil {
		return fmt.Errorf("添加 DNS 记录失败：%w", err)
	}

	s.logger.Info("DNS 记录创建成功",
		zap.String("type", recordType),
		zap.String("name", name),
		zap.String("domain", zone))

	return nil
}

// UpdateDNSRecord 更新 DNS 记录（全功能模式）
func (s *DDNSOperationService) UpdateDNSRecord(config *model.Service, recordType string, name string, value string, ttl int) error {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	// 1. 获取关联的 DDNS 配置
	ddnsConfig, err := s.getDDNSConfig(config.DDNSConfigID)
	if err != nil {
		return fmt.Errorf("获取 DDNS 配置失败：%w", err)
	}

	// 2. 创建 DNS Provider
	providerConfig := dnsprovider.ProviderConfig{
		Provider:        dnsprovider.ProviderType(ddnsConfig.Provider),
		Domain:          ddnsConfig.Domain,
		APIToken:        ddnsConfig.Token,
		AccessKeyID:     ddnsConfig.AuthUsername,
		AccessKeySecret: ddnsConfig.AuthPassword,
		SecretId:        ddnsConfig.AuthUsername,
		SecretKey:       ddnsConfig.AuthPassword,
	}

	provider, err := dnsprovider.NewDNSProvider(providerConfig)
	if err != nil {
		return fmt.Errorf("创建 DNS Provider 失败：%w", err)
	}

	// 3. 构建新的 DNS 记录
	newRecord := &dnsprovider.DNSRecord{
		Type:  dnsprovider.RecordType(recordType),
		Name:  name,
		Value: value,
		TTL:   ttl,
	}

	// 4. 使用 SetRecords 覆盖现有记录（会自动删除旧记录并创建新记录）
	zone := ddnsConfig.Domain
	libdnsRecord := newRecord.ToLibdnsRecord()

	s.logger.Info("开始更新 DNS 记录",
		zap.String("type", recordType),
		zap.String("name", name),
		zap.String("value", value),
		zap.String("domain", zone))

	_, err = provider.SetRecords(ctx, zone, []libdns.Record{libdnsRecord})
	if err != nil {
		return fmt.Errorf("更新 DNS 记录失败：%w", err)
	}

	s.logger.Info("DNS 记录更新成功",
		zap.String("type", recordType),
		zap.String("name", name),
		zap.String("domain", zone))

	return nil
}

// DeleteDNSRecord 删除 DNS 记录（全功能模式）
func (s *DDNSOperationService) DeleteDNSRecord(config *model.Service, recordType string, name string) error {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	// 1. 获取关联的 DDNS 配置
	ddnsConfig, err := s.getDDNSConfig(config.DDNSConfigID)
	if err != nil {
		return fmt.Errorf("获取 DDNS 配置失败：%w", err)
	}

	// 2. 创建 DNS Provider
	providerConfig := dnsprovider.ProviderConfig{
		Provider:        dnsprovider.ProviderType(ddnsConfig.Provider),
		Domain:          ddnsConfig.Domain,
		APIToken:        ddnsConfig.Token,
		AccessKeyID:     ddnsConfig.AuthUsername,
		AccessKeySecret: ddnsConfig.AuthPassword,
		SecretId:        ddnsConfig.AuthUsername,
		SecretKey:       ddnsConfig.AuthPassword,
	}

	provider, err := dnsprovider.NewDNSProvider(providerConfig)
	if err != nil {
		return fmt.Errorf("创建 DNS Provider 失败：%w", err)
	}

	// 3. 先获取所有记录
	records, err := provider.GetRecords(ctx, ddnsConfig.Domain)
	if err != nil {
		return fmt.Errorf("获取 DNS 记录失败：%w", err)
	}

	// 4. 找到要删除的记录
	var targetRecord *libdns.Record
	for _, rec := range records {
		if rec.Type == recordType && rec.Name == name {
			targetRecord = &rec
			break
		}
	}

	if targetRecord == nil {
		s.logger.Warn("DNS 记录不存在，跳过删除",
			zap.String("type", recordType),
			zap.String("name", name))
		return nil
	}

	// 5. 删除记录
	s.logger.Info("开始删除 DNS 记录",
		zap.String("type", recordType),
		zap.String("name", name),
		zap.String("domain", ddnsConfig.Domain))

	_, err = provider.DeleteRecords(ctx, ddnsConfig.Domain, []libdns.Record{*targetRecord})
	if err != nil {
		return fmt.Errorf("删除 DNS 记录失败：%w", err)
	}

	s.logger.Info("DNS 记录删除成功",
		zap.String("type", recordType),
		zap.String("name", name),
		zap.String("domain", ddnsConfig.Domain))

	return nil
}

// getDDNSConfig 获取关联的 DDNS 配置
func (s *DDNSOperationService) getDDNSConfig(configID string) (*model.Service, error) {
	// 从 Service 表中查询 ID=configID 且 Type=DDNS 的记录
	var ddnsService model.Service
	if err := s.db.Where("id = ? AND type = 'DDNS'", configID).First(&ddnsService).Error; err != nil {
		return nil, fmt.Errorf("查询 DDNS 配置失败：%w", err)
	}

	return &ddnsService, nil
}

// SyncMeshSeedToDNS 同步 MeshSeed 到 DNS TXT 记录（带重试机制）
func (s *DDNSOperationService) SyncMeshSeedToDNS(networkID uint64, seedString string, ddnsServiceID string) error {
	const maxRetries = 3
	var lastErr error

	// 查询 DDNS 配置
	var ddnsService model.Service
	if err := s.db.First(&ddnsService, ddnsServiceID).Error; err != nil {
		return fmt.Errorf("查询 DDNS 服务失败：%w", err)
	}

	// 查询网络获取前缀
	var network model.Network
	if err := s.db.First(&network, networkID).Error; err != nil {
		return fmt.Errorf("查询网络失败：%w", err)
	}

	// 重试逻辑（指数退避）
	for attempt := 1; attempt <= maxRetries; attempt++ {
		lastErr = s.doSyncMeshSeedToDNS(&network, &ddnsService, seedString)
		if lastErr == nil {
			// 成功，更新状态
			s.updateSyncStatus(networkID, "success", "")
			s.logger.Info("MeshSeed 同步到 DNS 成功",
				zap.Uint64("network_id", networkID),
				zap.Int("attempt", attempt))
			return nil
		}

		// 失败，记录日志
		s.logger.Warn("MeshSeed 同步失败",
			zap.Uint64("network_id", networkID),
			zap.Int("attempt", attempt),
			zap.Error(lastErr))

		// 等待后重试（指数退避：1s, 2s, 4s...）
		if attempt < maxRetries {
			waitTime := time.Duration(1<<uint(attempt-1)) * time.Second
			time.Sleep(waitTime)
		}
	}

	// 全部失败，更新状态
	s.updateSyncStatus(networkID, "failed", fmt.Sprintf("重试%d次失败：%v", maxRetries, lastErr))
	return fmt.Errorf("同步失败：%w", lastErr)
}

// doSyncMeshSeedToDNS 执行实际的同步操作
func (s *DDNSOperationService) doSyncMeshSeedToDNS(network *model.Network, ddnsService *model.Service, seedString string) error {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	// 1. 创建 DNS Provider
	providerConfig := dnsprovider.ProviderConfig{
		Provider:        dnsprovider.ProviderType(ddnsService.Provider),
		Domain:          ddnsService.Domain,
		APIToken:        ddnsService.Token,
		AccessKeyID:     ddnsService.AuthUsername,
		AccessKeySecret: ddnsService.AuthPassword,
		SecretId:        ddnsService.AuthUsername,
		SecretKey:       ddnsService.AuthPassword,
	}

	provider, err := dnsprovider.NewDNSProvider(providerConfig)
	if err != nil {
		return fmt.Errorf("创建 DNS Provider 失败：%w", err)
	}

	// 2. 构建 TXT 记录名称
	txtRecordName := network.DDNSPrefix
	if txtRecordName == "" {
		return fmt.Errorf("DDNS 前缀为空")
	}

	// 3. 加密 MeshSeed（AES-256-GCM）
	encryptedSeed, err := s.encryptMeshSeed(seedString, network.ID)
	if err != nil {
		return fmt.Errorf("加密 MeshSeed 失败：%w", err)
	}

	s.logger.Info("开始同步 MeshSeed 到 DNS",
		zap.String("record_name", txtRecordName),
		zap.String("domain", ddnsService.Domain))

	// 4. 创建/更新 TXT 记录
	zone := ddnsService.Domain
	libdnsRecord := libdns.Record{
		Type:  "TXT",
		Name:  txtRecordName,
		Value: encryptedSeed,
		TTL:   time.Duration(600) * time.Second,
	}

	// 先尝试删除旧记录（如果存在）
	_, err = provider.DeleteRecords(ctx, zone, []libdns.Record{libdnsRecord})
	if err != nil {
		s.logger.Debug("删除旧记录失败（可能不存在）",
			zap.String("name", txtRecordName),
			zap.Error(err))
	}

	// 添加新记录
	_, err = provider.AppendRecords(ctx, zone, []libdns.Record{libdnsRecord})
	if err != nil {
		return fmt.Errorf("添加 DNS 记录失败：%w", err)
	}

	s.logger.Info("MeshSeed 同步到 DNS 成功",
		zap.String("record_name", txtRecordName),
		zap.String("domain", ddnsService.Domain))

	return nil
}

// encryptMeshSeed 加密 MeshSeed（AES-256-GCM）
func (s *DDNSOperationService) encryptMeshSeed(plaintext string, networkID uint64) (string, error) {
	// TODO: 实现 AES-256-GCM 加密
	// 密钥派生：SHA256("meshray-ddns" + Network.Secret)
	// 目前先返回明文（P3 阶段实现）
	return plaintext, nil
}

// updateSyncStatus 更新同步状态
func (s *DDNSOperationService) updateSyncStatus(networkID uint64, status, message string) {
	// 更新 NetworkDDNSBinding 表
	var binding model.NetworkDDNSBinding
	if err := s.db.Where("network_id = ?", networkID).First(&binding).Error; err == nil {
		binding.Status = status
		now := time.Now()
		binding.LastSyncAt = &now
		binding.SyncMessage = message
		s.db.Save(&binding)
	}
}
