// internal/service/chat_service.go
package service

import (
	"context"
	"encoding/json"
	"fmt"
	"time"
	"websocket-server/internal/model"
	"websocket-server/internal/repository"

	"github.com/redis/go-redis/v9"
)

type ChatService struct {
	repo  *repository.ChatRepository
	redis *redis.Client
}

func NewChatService(repo *repository.ChatRepository, redisClient *redis.Client) *ChatService {
	return &ChatService{
		repo:  repo,
		redis: redisClient,
	}
}

// SendMessage handles sending a new chat message
func (s *ChatService) SendMessage(ctx context.Context, senderID string, req *model.ChatMessageRequest) (*model.ChatMessage, error) {
	if len(req.Content) == 0 || len(req.Content) > 5000 {
		return nil, fmt.Errorf("message content must be between 1 and 5000 characters")
	}

	room, err := s.repo.CreateOrGetRoom(ctx, senderID, req.ReceiverID)
	if err != nil {
		return nil, err
	}

	msg := &model.ChatMessage{
		RoomID:     room.ID,
		SenderID:   senderID,
		ReceiverID: req.ReceiverID,
		Content:    req.Content,
		ReplyToID:  req.ReplyToID,
		IsRead:     false,
		CreatedAt:  time.Now(),
	}

	err = s.repo.SaveMessage(ctx, msg)
	if err != nil {
		return nil, err
	}

	s.cacheMessage(ctx, msg)

	return msg, nil
}

// GetMessageHistory retrieves chat history with caching
func (s *ChatService) GetMessageHistory(ctx context.Context, customerID, otherCustomerID string, limit, offset int) ([]*model.ChatMessage, error) {
	if limit <= 0 || limit > 100 {
		limit = 50
	}

	// Try cache first (only for first page)
	if offset == 0 {
		cached, err := s.getCachedHistory(ctx, customerID, otherCustomerID, limit)
		if err == nil && len(cached) > 0 {
			return cached, nil
		}
	}

	// Fetch from database
	messages, err := s.repo.GetMessageHistory(ctx, customerID, otherCustomerID, limit, offset)
	if err != nil {
		return nil, err
	}

	// Cache first page
	if offset == 0 && len(messages) > 0 {
		s.cacheHistory(ctx, customerID, otherCustomerID, messages)
	}

	return messages, nil
}

// MarkAsRead marks messages as read
func (s *ChatService) MarkAsRead(ctx context.Context, receiverID, senderID string) error {
	return s.repo.MarkMessagesAsRead(ctx, receiverID, senderID)
}

// GetUserRooms retrieves all chat rooms for a customer
func (s *ChatService) GetUserRooms(ctx context.Context, customerID string) ([]*model.ChatRoom, error) {
	return s.repo.GetUserRooms(ctx, customerID)
}

// Cache helpers
func (s *ChatService) cacheMessage(ctx context.Context, msg *model.ChatMessage) {
	key := s.getCacheKey(msg.SenderID, msg.ReceiverID)
	data, _ := json.Marshal(msg)
	s.redis.LPush(ctx, key, data)
	s.redis.LTrim(ctx, key, 0, 49) // Keep last 50 messages
	s.redis.Expire(ctx, key, 1*time.Hour)
}

func (s *ChatService) getCachedHistory(ctx context.Context, customer1ID, customer2ID string, limit int) ([]*model.ChatMessage, error) {
	key := s.getCacheKey(customer1ID, customer2ID)
	data, err := s.redis.LRange(ctx, key, 0, int64(limit-1)).Result()
	if err != nil {
		return nil, err
	}

	var messages []*model.ChatMessage
	for _, d := range data {
		var msg model.ChatMessage
		if err := json.Unmarshal([]byte(d), &msg); err == nil {
			messages = append(messages, &msg)
		}
	}

	return messages, nil
}

func (s *ChatService) cacheHistory(ctx context.Context, customer1ID, customer2ID string, messages []*model.ChatMessage) {
	key := s.getCacheKey(customer1ID, customer2ID)
	for i := len(messages) - 1; i >= 0; i-- {
		data, _ := json.Marshal(messages[i])
		s.redis.RPush(ctx, key, data)
	}
	s.redis.Expire(ctx, key, 1*time.Hour)
}

func (s *ChatService) getCacheKey(customer1ID, customer2ID string) string {
	if customer1ID > customer2ID {
		customer1ID, customer2ID = customer2ID, customer1ID
	}
	return fmt.Sprintf("chat:history:%s:%s", customer1ID, customer2ID)
}
