package service

import (
	"context"
	"errors"
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"

	"git.zkcoi.com/zkcoi/meshray/internal/dnsprovider"
	"git.zkcoi.com/zkcoi/meshray/internal/model"
	"git.zkcoi.com/zkcoi/meshray/internal/store/sqlite"
	"github.com/google/uuid"
	"github.com/libdns/libdns"
	"gorm.io/gorm"
)

// ServiceService 服务管理服务
type ServiceService struct {
	store *sqlite.Store
}

// NewServiceService 创建服务服务实例
func NewServiceService(store *sqlite.Store) *ServiceService {
	return &ServiceService{store: store}
}

// ListServices 获取服务列表（支持按类型筛选）
func (s *ServiceService) ListServices(serverType string) ([]model.Service, error) {
	var services []model.Service
	query := s.store.DB().Order("created_at desc")
	if serverType != "" {
		// 支持大小写不敏感匹配
		query = query.Where("LOWER(type) = LOWER(?)", serverType)
	}
	err := query.Find(&services).Error
	return services, err
}

// GetServiceByID 根据 ID 获取服务
func (s *ServiceService) GetServiceByID(id string) (*model.Service, error) {
	var service model.Service
	if err := s.store.DB().Where("id = ?", id).First(&service).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("服务不存在")
		}
		return nil, err
	}
	return &service, nil
}

// CreateService 创建服务
func (s *ServiceService) CreateService(req *model.Service) (*model.Service, error) {
	if req.Name == "" {
		return nil, errors.New("服务名称不能为空")
	}
	if req.Type == "" {
		return nil, errors.New("服务类型不能为空")
	}

	// 强制转换为大写以保持一致性
	req.Type = strings.ToUpper(req.Type)

	// 校验支持的类型
	allowedTypes := map[string]bool{
		"STUN": true, "TURN": true, "DDNS": true, "TUN": true, "CUSTOM": true,
	}
	if !allowedTypes[req.Type] {
		return nil, fmt.Errorf("不支持的服务类型: %s", req.Type)
	}

	// 地址和端口校验（除 TUN 外通常需要）
	if req.Type != "TUN" {
		if req.Address == "" {
			return nil, errors.New("服务器地址不能为空")
		}
		if req.Port <= 0 || req.Port > 65535 {
			return nil, errors.New("端口号无效")
		}
	}

	// DDNS 鉴权校验（基础设施模式）
	if req.Type == "DDNS" && req.ConfigMode == "infrastructure" {
		if req.Provider == "" {
			return nil, errors.New("请选择 DNS 服务商")
		}
		if req.Domain == "" {
			return nil, errors.New("请输入根域名")
		}
		// 根据服务商校验认证信息
		switch req.Provider {
		case "cloudflare":
			if req.Token == "" {
				return nil, errors.New("请输入 API Token")
			}
		case "aliyun":
			if req.AuthUsername == "" || req.AuthPassword == "" {
				return nil, errors.New("请输入 AccessKey ID 和 Secret")
			}
		case "tencent":
			if req.AuthUsername == "" || req.AuthPassword == "" {
				return nil, errors.New("请输入 SecretId 和 SecretKey")
			}
		}
	}

	// DDNS 全功能模式校验
	if req.Type == "DDNS" && req.ConfigMode == "fullservice" {
		if req.DDNSConfigID == "" {
			return nil, errors.New("请选择 DDNS 配置")
		}
		if req.RecordType == "" {
			return nil, errors.New("请选择记录类型")
		}
		// 根据记录类型校验字段
		switch req.RecordType {
		case "A", "AAAA":
			if req.Subdomain == "" {
				return nil, errors.New("请输入主机记录")
			}
			if req.TargetIP == "" {
				return nil, errors.New("请输入目标 IP")
			}
			if req.Port <= 0 {
				return nil, errors.New("请输入检测端口")
			}
		case "TXT":
			if req.TXTRecordName == "" {
				return nil, errors.New("请输入 TXT 记录名称")
			}
			if req.TXTValue == "" {
				return nil, errors.New("请输入 TXT 记录值")
			}
		case "CNAME":
			if req.CNAMETarget == "" {
				return nil, errors.New("请输入目标域名")
			}
		}
	}

	// 生成 ID
	if req.ID == "" {
		req.ID = uuid.New().String()
	}

	// 如果是 DDNS 全功能模式，先创建 DNS 记录
	if req.Type == "DDNS" && req.ConfigMode == "fullservice" {
		// 使用事务确保原子性
		tx := s.store.DB().Begin()
		defer func() {
			if r := recover(); r != nil {
				tx.Rollback()
			}
		}()

		// 1. 获取关联的 DDNS 配置
		var ddnsConfig model.Service
		if err := tx.Where("id = ?", req.DDNSConfigID).First(&ddnsConfig).Error; err != nil {
			tx.Rollback()
			return nil, fmt.Errorf("获取 DDNS 配置失败：%w", err)
		}

		// 2. 确定记录类型、名称和值
		var recordType, name, value string
		switch req.RecordType {
		case "A", "AAAA":
			recordType = req.RecordType
			name = req.Subdomain
			value = req.TargetIP
		case "TXT":
			recordType = req.RecordType
			name = req.TXTRecordName
			value = req.TXTValue
		case "CNAME":
			recordType = req.RecordType
			name = req.Subdomain
			value = req.CNAMETarget
		default:
			tx.Rollback()
			return nil, errors.New("不支持的记录类型")
		}

		// 3. 创建 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 {
			tx.Rollback()
			return nil, fmt.Errorf("创建 DNS Provider 失败：%w", err)
		}

		// 4. 构建并添加 DNS 记录
		dnsRecord := &dnsprovider.DNSRecord{
			Type:  dnsprovider.RecordType(recordType),
			Name:  name,
			Value: value,
			TTL:   req.TTL,
		}

		ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
		defer cancel()

		_, err = provider.AppendRecords(ctx, ddnsConfig.Domain, []libdns.Record{dnsRecord.ToLibdnsRecord()})
		if err != nil {
			tx.Rollback()
			return nil, fmt.Errorf("创建 DNS 记录失败：%w", err)
		}

		// 5. DNS 记录创建成功，保存到数据库
		if err := tx.Create(req).Error; err != nil {
			tx.Rollback()
			return nil, err
		}

		tx.Commit()
		return req, nil
	}

	// 其他情况直接保存
	if err := s.store.DB().Create(req).Error; err != nil {
		return nil, err
	}
	return req, nil
}

// UpdateService 更新服务
func (s *ServiceService) UpdateService(id string, updates map[string]interface{}) (*model.Service, error) {
	var service model.Service
	if err := s.store.DB().Where("id = ?", id).First(&service).Error; err != nil {
		return nil, errors.New("服务不存在")
	}

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

// DeleteService 删除服务
func (s *ServiceService) DeleteService(id string) error {
	var service model.Service
	if err := s.store.DB().Where("id = ?", id).First(&service).Error; err != nil {
		return errors.New("服务不存在")
	}
	return s.store.DB().Delete(&service).Error
}

// TestServiceConnectivity 测试服务连通性
func (s *ServiceService) TestServiceConnectivity(id string) (string, error) {
	var service model.Service
	if err := s.store.DB().Where("id = ?", id).First(&service).Error; err != nil {
		return "", errors.New("服务不存在")
	}

	addr := net.JoinHostPort(service.Address, strconv.Itoa(service.Port))

	if service.Type == "STUN" {
		// STUN 使用 UDP 测试
		conn, err := net.DialTimeout("udp", addr, 5*time.Second)
		if err != nil {
			return "unreachable", nil
		}
		conn.Close()
		return "ok", nil
	}

	// 其他使用 TCP 测试
	conn, err := net.DialTimeout("tcp", addr, 5*time.Second)
	if err != nil {
		return "unreachable", nil
	}
	conn.Close()
	return "ok", nil
}
