package nats

import (
	"crypto/tls"
	"errors"
	"fmt"
	"leaf/log"
	"strings"
	"sync"
	"time"

	"github.com/nats-io/nats.go"
)

var (
	ErrConnectionClosed = errors.New("NATS connection closed")
	ErrRequestTimeout   = errors.New("request timeout")
)

// Config 配置NATSCluster
type Config struct {
	Servers        []string      // NATS服务器地址列表
	User           string        // 用户名
	Password       string        // 密码
	Token          string        // 认证token
	TLSConfig      *tls.Config   // TLS配置
	MaxReconnects  int           // 最大重连次数，-1表示无限重连
	ReconnectWait  time.Duration // 重连等待时间
	ConnectTimeout time.Duration // 连接超时时间
	PingInterval   time.Duration // 心跳检测间隔
	ClientName     string        // 客户端名称（用于监控）
}

// NATSCluster 封装NATS通信层
type NATSCluster struct {
	conn      *nats.Conn
	subs      map[string]*nats.Subscription
	subsMutex sync.Mutex
	closed    bool
}

// NewNATSCluster 创建NATS集群实例
func NewNATSCluster(cfg Config) (*NATSCluster, error) {
	opts := []nats.Option{
		nats.Name(cfg.ClientName),
		nats.Timeout(cfg.ConnectTimeout),
		nats.PingInterval(cfg.PingInterval),
		nats.MaxPingsOutstanding(3),
	}

	// 认证配置
	switch {
	case cfg.User != "" && cfg.Password != "":
		opts = append(opts, nats.UserInfo(cfg.User, cfg.Password))
	case cfg.Token != "":
		opts = append(opts, nats.Token(cfg.Token))
	}

	// TLS配置
	if cfg.TLSConfig != nil {
		opts = append(opts, nats.Secure(cfg.TLSConfig))
	}

	// 重连配置
	opts = append(opts, nats.MaxReconnects(cfg.MaxReconnects))
	opts = append(opts, nats.ReconnectWait(cfg.ReconnectWait))

	// 状态变更回调
	opts = append(opts, nats.ReconnectHandler(func(conn *nats.Conn) {
		log.Debug("NATS重新连接成功 [%s]", conn.ConnectedUrl())
	}))

	opts = append(opts, nats.DisconnectErrHandler(func(conn *nats.Conn, err error) {
		log.Error("NATS连接断开: %v", err)
	}))

	opts = append(opts, nats.ClosedHandler(func(conn *nats.Conn) {
		log.Debug("NATS连接永久关闭")
	}))

	opts = append(opts, nats.ErrorHandler(func(conn *nats.Conn, sub *nats.Subscription, err error) {
		log.Error("NATS错误: %v", err)
	}))

	// 建立连接
	conn, err := nats.Connect(strings.Join(cfg.Servers, ","), opts...)
	if err != nil {
		return nil, fmt.Errorf("NATS连接失败: %w", err)
	}

	return &NATSCluster{
		conn: conn,
		subs: make(map[string]*nats.Subscription),
	}, nil
}

// Call 异步RPC调用
func (c *NATSCluster) Call(serverType string, data []byte) error {
	if c.closed {
		return ErrConnectionClosed
	}

	subject := fmt.Sprintf("rpc.%s", serverType)
	if err := c.conn.Publish(subject, data); err != nil {
		return fmt.Errorf("发布失败: %w", err)
	}
	return nil
}

// Request 同步RPC调用
func (c *NATSCluster) Request(serverType string, data []byte, timeout time.Duration) ([]byte, error) {
	if c.closed {
		return nil, ErrConnectionClosed
	}

	subject := fmt.Sprintf("rpc.%s", serverType)
	msg, err := c.conn.Request(subject, data, timeout)
	if err != nil {
		if errors.Is(err, nats.ErrTimeout) {
			return nil, ErrRequestTimeout
		}
		return nil, fmt.Errorf("请求失败: %w", err)
	}
	return msg.Data, nil
}

// RegisterHandler 注册消息处理器（单消费者）
func (c *NATSCluster) RegisterHandler(serverType string, handler func([]byte)) error {
	return c.registerHandlerInternal(serverType, "", handler)
}

// RegisterQueueHandler 注册队列处理器（负载均衡）
func (c *NATSCluster) RegisterQueueHandler(serverType, queueGroup string, handler func([]byte)) error {
	return c.registerHandlerInternal(serverType, queueGroup, handler)
}

// registerHandlerInternal 内部注册实现
func (c *NATSCluster) registerHandlerInternal(serverType, queueGroup string, handler func([]byte)) error {
	if c.closed {
		return ErrConnectionClosed
	}

	subject := fmt.Sprintf("rpc.%s", serverType)
	c.subsMutex.Lock()
	defer c.subsMutex.Unlock()

	// 避免重复订阅
	if _, exists := c.subs[subject]; exists {
		return fmt.Errorf("主题已注册: %s", subject)
	}

	// 创建订阅
	var sub *nats.Subscription
	var err error

	if queueGroup != "" {
		sub, err = c.conn.QueueSubscribe(subject, queueGroup, func(msg *nats.Msg) {
			log.Debug("收到队列请求 [%s:%s]: %s", subject, queueGroup, string(msg.Data))
			handler(msg.Data)
		})
	} else {
		sub, err = c.conn.Subscribe(subject, func(msg *nats.Msg) {
			log.Debug("收到请求 [%s]: %s", subject, string(msg.Data))
			handler(msg.Data)
		})
	}

	if err != nil {
		return fmt.Errorf("订阅失败: %w", err)
	}

	c.subs[subject] = sub
	return nil
}

// Close 安全关闭连接
func (c *NATSCluster) Close() {
	if c.closed {
		return
	}
	c.closed = true

	// 取消所有订阅
	c.subsMutex.Lock()
	for subject, sub := range c.subs {
		if err := sub.Unsubscribe(); err != nil {
			log.Error("取消订阅失败 [%s]: %v", subject, err)
		}
		delete(c.subs, subject)
	}
	c.subsMutex.Unlock()

	// 优雅关闭连接
	if err := c.conn.Drain(); err != nil {
		log.Error("连接关闭失败: %v", err)
	}
	c.conn.Close()
}

// IsConnected 检查连接状态
func (c *NATSCluster) IsConnected() bool {
	return !c.closed && c.conn.IsConnected()
}

// Stats 获取连接统计信息
func (c *NATSCluster) Stats() nats.Statistics {
	return c.conn.Stats()
}
