package handler

import (
	"encoding/json"
	"fmt"
	"net/http"
	"regexp"
	"strings"

	"git.zkcoi.com/zkcoi/meshray/internal/model"
	"git.zkcoi.com/zkcoi/meshray/pkg/shortid"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

// DDNSUsageHandler DDNS Usage 管理 Handler
type DDNSUsageHandler struct {
	db     *gorm.DB
	logger *zap.Logger
}

// NewDDNSUsageHandler 创建 DDNS Usage Handler
func NewDDNSUsageHandler(db *gorm.DB, logger *zap.Logger) *DDNSUsageHandler {
	return &DDNSUsageHandler{
		db:     db,
		logger: logger,
	}
}

// CreateUsageRequest 创建 Usage 请求
type CreateUsageRequest struct {
	ServiceID    string `json:"service_id"`    // DDNS 服务 ID
	PrefixMode   string `json:"prefix_mode"`   // "auto" | "custom"
	CustomPrefix string `json:"custom_prefix"` // 自定义前缀（仅 custom 模式需要）
	NetworkID    uint64 `json:"network_id"`    // 绑定的网络 ID
	NetworkName  string `json:"network_name"`  // 网络名称（用于显示）
}

// CreateUsage 创建 DDNS Usage
// POST /api/v1/ddns/usages
func (h *DDNSUsageHandler) CreateUsage(c *gin.Context) {
	var req CreateUsageRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误"})
		return
	}

	// 验证必填字段
	if req.ServiceID == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "请选择 DDNS 服务"})
		return
	}

	if req.PrefixMode != "auto" && req.PrefixMode != "custom" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的前缀模式"})
		return
	}

	// 开启事务
	tx := h.db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 1. 验证 DDNS 服务存在
	var service model.ExternalService
	if err := tx.First(&service, req.ServiceID).Error; err != nil {
		tx.Rollback()
		c.JSON(http.StatusNotFound, gin.H{"error": "DDNS 服务不存在"})
		return
	}

	// 2. 解析配置获取域名
	var config map[string]interface{}
	if err := json.Unmarshal([]byte(service.Config), &config); err != nil {
		tx.Rollback()
		c.JSON(http.StatusInternalServerError, gin.H{"error": "解析 DDNS 配置失败"})
		return
	}
	domain, _ := config["domain"].(string)
	if domain == "" {
		tx.Rollback()
		c.JSON(http.StatusBadRequest, gin.H{"error": "DDNS 配置缺少域名"})
		return
	}

	// 3. 根据模式生成前缀
	var recordPrefix string
	if req.PrefixMode == "auto" {
		// ✅ 算法生成：Base64(NetworkID)
		recordPrefix = shortid.EncodeID(req.NetworkID)
		h.logger.Debug("自动生成前缀",
			zap.Uint64("network_id", req.NetworkID),
			zap.String("prefix", recordPrefix))

	} else if req.PrefixMode == "custom" {
		// ✅ 用户自定义：验证格式 + 检测占用
		if err := validateCustomPrefix(req.CustomPrefix); err != nil {
			tx.Rollback()
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		// 检测是否被占用
		var count int64
		tx.Model(&model.DDNSUsage{}).
			Where("service_id = ? AND record_prefix = ?", req.ServiceID, req.CustomPrefix).
			Count(&count)

		if count > 0 {
			tx.Rollback()
			c.JSON(http.StatusBadRequest, gin.H{"error": "该前缀已被其他组网占用"})
			return
		}

		recordPrefix = req.CustomPrefix
		h.logger.Debug("使用自定义前缀",
			zap.String("prefix", req.CustomPrefix))
	}

	// 4. 创建 Usage 记录
	usage := &model.DDNSUsage{
		ID:           uuid.New().String(),
		ProviderID:   req.ServiceID,   // ✅ 使用 ProviderID 字段
		UsageType:    "meshseed_sync", // MeshSeed 同步用途
		PrefixMode:   req.PrefixMode,
		RecordPrefix: recordPrefix,
		RecordType:   "TXT", // MeshSeed 同步固定使用 TXT 记录
		Description:  fmt.Sprintf("MeshSeed 同步 - %s", req.NetworkName),
		IsExclusive:  true, // 独占性，一个前缀只能绑定一个网络
	}

	if err := tx.Create(usage).Error; err != nil {
		tx.Rollback()
		h.logger.Error("创建 Usage 失败", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "创建失败：" + err.Error()})
		return
	}

	// 5. 创建绑定关系
	binding := &model.NetworkDDNSBinding{
		ID:         uuid.New().String(),
		NetworkID:  req.NetworkID,
		UsageID:    usage.ID,
		ProviderID: req.ServiceID,
		Status:     "active",
	}

	if err := tx.Create(binding).Error; err != nil {
		tx.Rollback()
		h.logger.Error("创建绑定关系失败", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "创建绑定失败：" + err.Error()})
		return
	}

	// 提交事务
	if err := tx.Commit().Error; err != nil {
		h.logger.Error("事务提交失败", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "提交失败"})
		return
	}

	// 构造完整域名
	fullDomain := fmt.Sprintf("_meshray.%s.%s", recordPrefix, domain)

	h.logger.Info("DDNS Usage 创建成功",
		zap.String("usage_id", usage.ID),
		zap.Uint64("network_id", req.NetworkID),
		zap.String("full_domain", fullDomain))

	c.JSON(http.StatusOK, gin.H{
		"message": "创建成功",
		"data": gin.H{
			"id":            usage.ID,
			"provider_id":   usage.ProviderID,
			"prefix_mode":   usage.PrefixMode,
			"record_prefix": recordPrefix,
			"full_domain":   fullDomain,
			"network_id":    req.NetworkID,
		},
	})
}

// CheckPrefixOccupied 检查前缀是否被占用
// GET /api/v1/ddns/check-prefix?service_id=xxx&prefix=yyy
func (h *DDNSUsageHandler) CheckPrefixOccupied(c *gin.Context) {
	serviceID := c.Query("service_id")
	prefix := c.Query("prefix")

	if serviceID == "" || prefix == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "缺少必要参数"})
		return
	}

	// 查询占用情况
	var count int64
	h.db.Model(&model.DDNSUsage{}).
		Where("service_id = ? AND record_prefix = ?", serviceID, prefix).
		Count(&count)

	c.JSON(http.StatusOK, gin.H{
		"data": gin.H{
			"occupied": count > 0,
			"count":    count,
		},
	})
}

// GetAvailableUsages 获取可用的 DDNS Usage 列表
// GET /api/v1/ddns/usages/available
func (h *DDNSUsageHandler) GetAvailableUsages(c *gin.Context) {
	serviceID := c.Query("service_id")

	// 查询所有 TXT 类型的 Usage
	query := h.db.Where("record_type = ?", "TXT").
		Preload("Provider")

	if serviceID != "" {
		query = query.Where("service_id = ?", serviceID)
	}

	var usages []model.DDNSUsage
	if err := query.Find(&usages).Error; err != nil {
		h.logger.Error("查询 Usage 列表失败", zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "查询失败"})
		return
	}

	// 构造返回数据
	type UsageVO struct {
		ID           string      `json:"id"`
		ProviderID   string      `json:"provider_id"`
		PrefixMode   string      `json:"prefix_mode"`
		RecordPrefix string      `json:"record_prefix"`
		RecordType   string      `json:"record_type"`
		Description  string      `json:"description"`
		IsOccupied   bool        `json:"is_occupied"`
		NetworkID    *uint64     `json:"network_id,omitempty"`
		FullDomain   string      `json:"full_domain"`
		Provider     interface{} `json:"provider,omitempty"`
	}

	result := make([]UsageVO, 0, len(usages))
	for _, usage := range usages {
		// 获取完整域名
		var provider model.ExternalService
		h.db.First(&provider, usage.ProviderID)

		var config map[string]interface{}
		json.Unmarshal([]byte(provider.Config), &config)
		domain, _ := config["domain"].(string)

		fullDomain := fmt.Sprintf("_meshray.%s.%s", usage.RecordPrefix, domain)

		// 从 NetworkDDNSBinding 表查询关联的 Network ID
		var networkID *uint64
		var binding model.NetworkDDNSBinding
		if err := h.db.Where("ddns_usage_id = ?", usage.ID).First(&binding).Error; err == nil {
			networkID = &binding.NetworkID
		}

		vo := UsageVO{
			ID:           usage.ID,
			ProviderID:   usage.ProviderID,
			PrefixMode:   usage.PrefixMode,
			RecordPrefix: usage.RecordPrefix,
			RecordType:   usage.RecordType,
			Description:  usage.Description,
			IsOccupied:   usage.IsExclusive,
			NetworkID:    networkID,
			FullDomain:   fullDomain,
		}

		if usage.Provider != nil {
			vo.Provider = gin.H{
				"id":   usage.Provider.ID,
				"name": usage.Provider.Name,
			}
		}

		result = append(result, vo)
	}

	c.JSON(http.StatusOK, gin.H{"data": result})
}

// validateCustomPrefix 验证自定义前缀
func validateCustomPrefix(prefix string) error {
	if prefix == "" {
		return fmt.Errorf("前缀不能为空")
	}

	if len(prefix) > 63 {
		return fmt.Errorf("前缀不能超过 63 个字符")
	}

	// DNS 标签规范
	matched, _ := regexp.MatchString(`^[a-zA-Z0-9_-]+$`, prefix)
	if !matched {
		return fmt.Errorf("前缀只能包含字母、数字、下划线和连字符")
	}

	// 系统保留字检查
	if strings.HasPrefix(prefix, "_meshray") {
		return fmt.Errorf("_meshray.* 前缀为系统保留，请使用自动生成模式")
	}

	return nil
}
