package service

import (
	"encoding/json"
	"sync"
	"time"

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

// NotificationService 通知服务
type NotificationService struct {
	db          *gorm.DB
	logger      *zap.Logger
	clients     map[uint]*NotificationClient // userID -> client
	mu          sync.RWMutex
	broadcastCh chan NotificationMessage
}

// NotificationClient WebSocket 通知客户端
type NotificationClient struct {
	userID   uint
	username string
	conn     *gin.Context
	msgCh    chan NotificationMessage
	done     chan struct{}
}

// NotificationMessage 通知消息
type NotificationMessage struct {
	Type      string                 `json:"type"`     // alert, system, update, ddns
	Priority  int                    `json:"priority"` // 1=low, 2=medium, 3=high
	Title     string                 `json:"title"`
	Message   string                 `json:"message"`
	Data      map[string]interface{} `json:"data,omitempty"`
	Timestamp time.Time              `json:"timestamp"`
}

// NewNotificationService 创建通知服务
func NewNotificationService(db *gorm.DB, logger *zap.Logger) *NotificationService {
	svc := &NotificationService{
		db:          db,
		logger:      logger,
		clients:     make(map[uint]*NotificationClient),
		broadcastCh: make(chan NotificationMessage, 100),
	}

	// 启动广播协程
	go svc.runBroadcaster()

	return svc
}

// runBroadcaster 运行广播协程
func (s *NotificationService) runBroadcaster() {
	for msg := range s.broadcastCh {
		s.mu.RLock()
		for _, client := range s.clients {
			select {
			case client.msgCh <- msg:
				// 发送成功
			default:
				// 通道已满，跳过
				s.logger.Warn("通知通道已满", zap.Uint("user_id", client.userID))
			}
		}
		s.mu.RUnlock()
	}
}

// RegisterClient 注册通知客户端
func (s *NotificationService) RegisterClient(userID uint, username string, msgCh chan NotificationMessage, done chan struct{}) {
	s.mu.Lock()
	defer s.mu.Unlock()

	client := &NotificationClient{
		userID:   userID,
		username: username,
		msgCh:    msgCh,
		done:     done,
	}

	s.clients[userID] = client
	s.logger.Info("用户已连接通知服务", zap.Uint("user_id", userID), zap.String("username", username))
}

// UnregisterClient 注销通知客户端
func (s *NotificationService) UnregisterClient(userID uint) {
	s.mu.Lock()
	defer s.mu.Unlock()

	if client, ok := s.clients[userID]; ok {
		close(client.done)
		delete(s.clients, userID)
		s.logger.Info("用户已断开通知服务", zap.Uint("user_id", userID))
	}
}

// SendToUser 发送通知给指定用户（并保存到数据库）
func (s *NotificationService) SendToUser(userID uint, msg NotificationMessage) {
	// 1. 保存到数据库
	notification := model.Notification{
		UserID:   userID,
		Type:     msg.Type,
		Priority: msg.Priority,
		Title:    msg.Title,
		Message:  msg.Message,
	}

	if msg.Data != nil {
		dataJSON, _ := json.Marshal(msg.Data)
		notification.Data = string(dataJSON)
	}

	if err := s.db.Create(&notification).Error; err != nil {
		s.logger.Error("保存通知失败", zap.Error(err))
	}

	// 2. 发送到 WebSocket 通道
	s.mu.RLock()
	defer s.mu.RUnlock()

	if client, ok := s.clients[userID]; ok {
		select {
		case client.msgCh <- msg:
			s.logger.Debug("通知已发送给用户",
				zap.Uint("user_id", userID),
				zap.String("type", msg.Type))
		default:
			s.logger.Warn("用户通知通道已满", zap.Uint("user_id", userID))
		}
	}
}

// Broadcast 广播通知给所有在线用户（并保存到数据库）
func (s *NotificationService) Broadcast(msg NotificationMessage) {
	msg.Timestamp = time.Now()

	// 保存到所有用户的数据库记录
	s.mu.RLock()
	for userID := range s.clients {
		notification := model.Notification{
			UserID:   userID,
			Type:     msg.Type,
			Priority: msg.Priority,
			Title:    msg.Title,
			Message:  msg.Message,
		}

		if msg.Data != nil {
			dataJSON, _ := json.Marshal(msg.Data)
			notification.Data = string(dataJSON)
		}

		s.db.Create(&notification)
	}
	s.mu.RUnlock()

	// 发送到 WebSocket 通道
	s.broadcastCh <- msg
	s.logger.Debug("通知已广播",
		zap.String("type", msg.Type),
		zap.Int("online_users", len(s.clients)))
}

// SendAlert 发送告警通知
func (s *NotificationService) SendAlert(userID uint, title, message string, data map[string]interface{}) {
	msg := NotificationMessage{
		Type:      "alert",
		Priority:  3, // high priority
		Title:     title,
		Message:   message,
		Data:      data,
		Timestamp: time.Now(),
	}
	s.SendToUser(userID, msg)
}

// SendSystemNotification 发送系统通知
func (s *NotificationService) SendSystemNotification(userID uint, title, message string) {
	msg := NotificationMessage{
		Type:      "system",
		Priority:  2, // medium priority
		Title:     title,
		Message:   message,
		Timestamp: time.Now(),
	}
	s.SendToUser(userID, msg)
}

// SendUpdateAvailable 发送更新可用通知
func (s *NotificationService) SendUpdateAvailable(version, notes, downloadURL string) {
	msg := NotificationMessage{
		Type:     "update",
		Priority: 2,
		Title:    "发现新版本",
		Message:  version,
		Data: map[string]interface{}{
			"version":      version,
			"notes":        notes,
			"download_url": downloadURL,
		},
		Timestamp: time.Now(),
	}
	s.Broadcast(msg)
}

// SendDDNSUpdate 发送 DDNS 更新通知
func (s *NotificationService) SendDDNSUpdate(serviceName, oldIP, newIP string) {
	data, _ := json.Marshal(gin.H{
		"service_name": serviceName,
		"old_ip":       oldIP,
		"new_ip":       newIP,
	})

	var dataMap map[string]interface{}
	json.Unmarshal(data, &dataMap)

	msg := NotificationMessage{
		Type:      "ddns",
		Priority:  1, // low priority
		Title:     "DDNS IP 已更新",
		Message:   serviceName,
		Data:      dataMap,
		Timestamp: time.Now(),
	}
	s.Broadcast(msg)
}

// GetOnlineUserCount 获取在线用户数
func (s *NotificationService) GetOnlineUserCount() int {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return len(s.clients)
}

// GetDB 返回数据库实例（用于 Handler 层查询）
func (s *NotificationService) GetDB() *gorm.DB {
	return s.db
}
