package otel

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/gogf/gf/v2/os/glog"
)

// ConnRecoveryManager 连接恢复管理器 - 处理OTel服务下线和恢复
type ConnRecoveryManager struct {
	manager        *Manager
	config         *Config
	mu             sync.RWMutex
	isConnected    bool
	lastCheckTime  time.Time
	checkInterval  time.Duration
	maxRetries     int
	currentRetries int
	ctx            context.Context
	cancel         context.CancelFunc
	stopChan       chan struct{}
	wg             sync.WaitGroup
}

// NewConnRecoveryManager 创建连接恢复管理器
func NewConnRecoveryManager(manager *Manager) *ConnRecoveryManager {
	ctx, cancel := context.WithCancel(context.Background())
	return &ConnRecoveryManager{
		manager:       manager,
		config:        manager.config,
		isConnected:   true,
		checkInterval: 30 * time.Second,
		maxRetries:    5, // 12 * 30秒 = 6分钟最大重试时间
		ctx:           ctx,
		cancel:        cancel,
		stopChan:      make(chan struct{}),
	}
}

// Start 启动连接恢复监控
func (cr *ConnRecoveryManager) Start() {
	cr.wg.Add(1)
	go cr.monitorConnection()
	glog.Info(nil, fmt.Sprintf("OTel连接恢复监控已启动, 检查间隔: %v, 最大重试次数: %d", cr.checkInterval, cr.maxRetries))
}

// Stop 停止连接恢复监控
func (cr *ConnRecoveryManager) Stop() {
	close(cr.stopChan)
	cr.cancel()
	cr.wg.Wait()
	glog.Info(nil, "OTel连接恢复监控已停止")
}

// monitorConnection 监控连接状态并在需要时恢复
func (cr *ConnRecoveryManager) monitorConnection() {
	defer cr.wg.Done()
	ticker := time.NewTicker(cr.checkInterval)
	defer ticker.Stop()

	for {
		select {
		case <-cr.stopChan:
			return
		case <-ticker.C:
			cr.checkAndRecover()
		}
	}
}

// checkAndRecover 检查并恢复连接
func (cr *ConnRecoveryManager) checkAndRecover() {
	cr.mu.Lock()
	defer cr.mu.Unlock()

	// 执行健康检查
	healthCheckCtx, cancel := context.WithTimeout(cr.ctx, 5*time.Second)
	defer cancel()

	err := cr.manager.HealthCheck(healthCheckCtx)

	if err != nil {
		cr.handleConnectionFailure()
		return
	}

	// 连接成功，重置重试计数
	if !cr.isConnected {
		cr.isConnected = true
		cr.currentRetries = 0
		glog.Info(nil, fmt.Sprintf("OTel服务已恢复连接: %s", cr.config.CollectorURL))
	}

	cr.lastCheckTime = time.Now()
}

// handleConnectionFailure 处理连接失败
func (cr *ConnRecoveryManager) handleConnectionFailure() {
	cr.isConnected = false
	cr.currentRetries++

	elapsedTime := time.Now().Sub(cr.lastCheckTime)
	glog.Warning(nil, fmt.Sprintf("OTel连接失败 [尝试 %d/%d]: %s, 已等待: %v",
		cr.currentRetries, cr.maxRetries, cr.config.CollectorURL, elapsedTime))

	// 检查是否超过最大重试次数
	if cr.currentRetries >= cr.maxRetries {
		glog.Error(nil, fmt.Sprintf("OTel服务连接超时: 超过最大重试次数 (%d), 服务地址: %s",
			cr.maxRetries, cr.config.CollectorURL))
	}
}

// IsConnected 检查是否连接正常
func (cr *ConnRecoveryManager) IsConnected() bool {
	cr.mu.RLock()
	defer cr.mu.RUnlock()
	return cr.isConnected
}

// GetConnectionStatus 获取连接状态信息
func (cr *ConnRecoveryManager) GetConnectionStatus() string {
	cr.mu.RLock()
	defer cr.mu.RUnlock()

	status := "connected"
	if !cr.isConnected {
		status = "disconnected"
	}

	return fmt.Sprintf("Status: %s, Retries: %d/%d, Endpoint: %s",
		status, cr.currentRetries, cr.maxRetries, cr.config.CollectorURL)
}

// GetLastCheckTime 获取最后一次检查时间
func (cr *ConnRecoveryManager) GetLastCheckTime() time.Time {
	cr.mu.RLock()
	defer cr.mu.RUnlock()
	return cr.lastCheckTime
}

// SetCheckInterval 设置检查间隔
func (cr *ConnRecoveryManager) SetCheckInterval(interval time.Duration) {
	cr.checkInterval = interval
}

// SetMaxRetries 设置最大重试次数
func (cr *ConnRecoveryManager) SetMaxRetries(maxRetries int) {
	cr.maxRetries = maxRetries
}

// ResetRetryCount 手动重置重试计数
func (cr *ConnRecoveryManager) ResetRetryCount() {
	cr.mu.Lock()
	defer cr.mu.Unlock()
	cr.currentRetries = 0
	cr.lastCheckTime = time.Now()
	glog.Info(nil, "OTel重试计数已重置")
}
