// Package corebind 的契约注册：向开源契约（meshray-contract）注册增强 Bind 工厂与引擎提供方。
package corebind

import (
	"sync"

	"git.zkcoi.com/zkcoi/meshray-contract"
	"git.zkcoi.com/zkcoi/meshray/core/engine"
	"go.uber.org/zap"
	"golang.zx2c4.com/wireguard/conn"
)

// engines 维护 networkID -> Engine 单例映射。
// EnhancedBind（收发接管）与 engineController（控制面）均通过 networkID 关联同一个 Engine，
// 使信令下发的候选地址、ICE 配置、层顺序都能落到接管该组网收发的 Engine 上。
var (
	enginesMu sync.Mutex
	engines   = make(map[string]*core.Engine)
)

// getOrCreateEngine 获取或创建指定组网的 Engine 单例（线程安全）
func getOrCreateEngine(networkID string, logger *zap.Logger) *core.Engine {
	enginesMu.Lock()
	defer enginesMu.Unlock()
	if e, ok := engines[networkID]; ok {
		return e
	}
	e := core.NewEngine(logger, core.NewMetrics())
	engines[networkID] = e
	return e
}

// engineController 适配 contract.EngineController，以 networkID 关联 Engine 单例，
// 供管理器在 enhanced 模式调用，无需直接依赖本包具体类型。
type engineController struct {
	networkID string
	engine    *core.Engine
}

func (c *engineController) Start() error { return c.engine.Start() }

func (c *engineController) Stop() error { return c.engine.Stop() }

// NotifyPeerCandidates 由信令层调用：注入对端候选地址并触发 P2P 建连
func (c *engineController) NotifyPeerCandidates(peerKey string, candidates []contract.Candidate) error {
	return c.engine.NotifyPeerInfo(peerKey, toCoreCandidates(candidates))
}

// SetICEConfig 更新 ICE/STUN/TURN 配置
func (c *engineController) SetICEConfig(cfg contract.ICEConfig) error {
	return c.engine.SetICEConfig(toCoreICEConfig(cfg))
}

// SetLayerOrder 设置传输层优先级顺序（策略核心配置）
func (c *engineController) SetLayerOrder(order []contract.Layer) error {
	c.engine.SetLayerOrder(toCoreLayerOrder(order))
	return nil
}

// GetStatus 查询引擎状态
func (c *engineController) GetStatus() (*contract.EngineStatus, error) {
	st, err := c.engine.GetStatus()
	if err != nil {
		return nil, err
	}
	return toContractStatus(st), nil
}

// init 向开源契约注册表注册增强 Bind 工厂与引擎提供方。
// 由管理器侧 core_enable.go 在 -tags meshray_core 构建下空白导入本包触发，
// 此时管理器侧 contract.GetBindFactory(true) / NewEngineController 才能取到实现；
// 默认构建不引入本包，原生直连（默认 Bind）始终可用。
func init() {
	contract.RegisterEnhancedBindFactory(func(listenPort int, networkID string, logger *zap.Logger) (conn.Bind, error) {
		return NewEnhancedBind(listenPort, networkID, logger)
	})
	contract.RegisterEngineProvider(func(networkID string, logger *zap.Logger) (contract.EngineController, error) {
		return &engineController{networkID: networkID, engine: getOrCreateEngine(networkID, logger)}, nil
	})
}
