package services

import (
	"context"
	"errors"
	"fmt"
	"time" // Add time import

	"veza-backend-api/internal/models"
	"veza-backend-api/internal/repositories"
	
	"github.com/google/uuid" // Add uuid import
	"go.uber.org/zap"
)

// RoomService gère la logique métier pour les rooms
type RoomService struct {
	roomRepo *repositories.RoomRepository
	messageRepo *repositories.ChatMessageRepository
	logger   *zap.Logger
}

// NewRoomService crée une nouvelle instance de RoomService
func NewRoomService(roomRepo *repositories.RoomRepository, messageRepo *repositories.ChatMessageRepository, logger *zap.Logger) *RoomService {
	return &RoomService{
		roomRepo: roomRepo,
		messageRepo: messageRepo,
		logger:   logger,
	}
}

// CreateRoomRequest représente une requête de création de room
type CreateRoomRequest struct {
	Name        string  `json:"name" binding:"required,min=1,max=255"`
	Description *string `json:"description,omitempty"`
	Type        string  `json:"type" binding:"required,oneof=public private direct"`
	IsPrivate   bool    `json:"is_private"`
}

// RoomResponse représente une réponse de room pour l'API
type RoomResponse struct {
	ID          uuid.UUID    `json:"id"`
	Name        string   `json:"name"`
	Description string   `json:"description,omitempty"`
	Type        string   `json:"type"`
	IsPrivate   bool     `json:"is_private"`
	CreatedBy   int64    `json:"created_by"`
	Participants []int64 `json:"participants"`
	CreatedAt   string   `json:"created_at"`
	UpdatedAt   string   `json:"updated_at"`
}

// CreateRoom crée une nouvelle room
func (s *RoomService) CreateRoom(ctx context.Context, userID int64, req CreateRoomRequest) (*RoomResponse, error) {
	if req.Name == "" {
		return nil, errors.New("room name is required")
	}
	
	// Créer la room
	room := &models.Room{
		Name:        req.Name,
		Description: "",
		Type:        req.Type,
		IsPrivate:   req.IsPrivate,
		CreatedBy:   userID,
	}
	
	if req.Description != nil {
		room.Description = *req.Description
	}
	
	if err := s.roomRepo.Create(ctx, room); err != nil {
		s.logger.Error("failed to create room", 
			zap.Error(err),
			zap.Int64("user_id", userID),
			zap.String("room_name", req.Name))
		return nil, fmt.Errorf("failed to create room: %w", err)
	}
	
	// Ajouter le créateur comme membre admin
	member := &models.RoomMember{
		RoomID: room.ID, // use uuid
		UserID: userID,
		Role:   "admin",
	}
	
	if err := s.roomRepo.AddMember(ctx, member); err != nil {
		s.logger.Error("failed to add creator as room member",
			zap.Error(err),
			zap.String("room_id", room.ID.String()),
			zap.Int64("user_id", userID))
		// Ne pas retourner d'erreur, la room est créée
	}
	
	s.logger.Info("room created successfully",
		zap.String("room_id", room.ID.String()),
		zap.Int64("user_id", userID),
		zap.String("room_name", room.Name))
	
	return &RoomResponse{
		ID:          room.ID,
		Name:        room.Name,
		Description: room.Description,
		Type:        room.Type,
		IsPrivate:   room.IsPrivate,
		CreatedBy:   room.CreatedBy,
		Participants: []int64{userID},
		CreatedAt:   room.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
		UpdatedAt:   room.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"),
	}, nil
}

// GetUserRooms récupère toutes les rooms d'un utilisateur
func (s *RoomService) GetUserRooms(ctx context.Context, userID int64) ([]*RoomResponse, error) {
	rooms, err := s.roomRepo.GetByUserID(ctx, userID)
	if err != nil {
		s.logger.Error("failed to get user rooms",
			zap.Error(err),
			zap.Int64("user_id", userID))
		return nil, fmt.Errorf("failed to get user rooms: %w", err)
	}
	
	responses := make([]*RoomResponse, 0, len(rooms))
	for _, room := range rooms {
		// Récupérer les membres pour avoir la liste des participants
		members, err := s.roomRepo.GetMembersByRoomID(ctx, room.ID)
		if err != nil {
			s.logger.Warn("failed to get room members",
				zap.Error(err),
				zap.String("room_id", room.ID.String()))
			members = []*models.RoomMember{}
		}
		
		participants := make([]int64, 0, len(members))
		for _, member := range members {
			participants = append(participants, member.UserID)
		}
		
		responses = append(responses, &RoomResponse{
			ID:          room.ID,
			Name:        room.Name,
			Description: room.Description,
			Type:        room.Type,
			IsPrivate:   room.IsPrivate,
			CreatedBy:   room.CreatedBy,
			Participants: participants,
			CreatedAt:   room.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
			UpdatedAt:   room.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"),
		})
	}
	
	return responses, nil
}

// GetRoom récupère une room par son ID
func (s *RoomService) GetRoom(ctx context.Context, roomID uuid.UUID) (*RoomResponse, error) {
	room, err := s.roomRepo.GetByID(ctx, roomID)
	if err != nil {
		s.logger.Error("failed to get room",
			zap.Error(err),
			zap.String("room_id", roomID.String()))
		return nil, fmt.Errorf("failed to get room: %w", err)
	}
	
	// Récupérer les membres
	members, err := s.roomRepo.GetMembersByRoomID(ctx, roomID)
	if err != nil {
		s.logger.Warn("failed to get room members",
			zap.Error(err),
			zap.String("room_id", roomID.String()))
		members = []*models.RoomMember{}
	}
	
	participants := make([]int64, 0, len(members))
	for _, member := range members {
		participants = append(participants, member.UserID)
	}
	
	return &RoomResponse{
		ID:          room.ID,
		Name:        room.Name,
		Description: room.Description,
		Type:        room.Type,
		IsPrivate:   room.IsPrivate,
		CreatedBy:   room.CreatedBy,
		Participants: participants,
		CreatedAt:   room.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
		UpdatedAt:   room.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"),
	}, nil
}

// AddMember ajoute un membre à une room
func (s *RoomService) AddMember(ctx context.Context, roomID uuid.UUID, userID int64) error {
	member := &models.RoomMember{
		RoomID: roomID,
		UserID: userID,
		Role:   "member",
	}
	
	if err := s.roomRepo.AddMember(ctx, member); err != nil {
		s.logger.Error("failed to add member to room",
			zap.Error(err),
			zap.String("room_id", roomID.String()),
			zap.Int64("user_id", userID))
		return fmt.Errorf("failed to add member: %w", err)
	}
	
	s.logger.Info("member added to room",
		zap.String("room_id", roomID.String()),
		zap.Int64("user_id", userID))
	
	return nil
}

// ChatMessageResponse pour la réponse d'historique
type ChatMessageResponse struct {
	ID             uuid.UUID `json:"id"`
	ConversationID uuid.UUID `json:"conversation_id"`
	SenderID       uuid.UUID `json:"sender_id"`
	Content        string    `json:"content"`
	MessageType    string    `json:"message_type"`
	CreatedAt      time.Time `json:"created_at"`
}

// GetRoomHistory récupère l'historique des messages d'une room
func (s *RoomService) GetRoomHistory(ctx context.Context, roomID uuid.UUID, limit, offset int) ([]ChatMessageResponse, error) {
	messages, err := s.messageRepo.GetConversationMessages(ctx, roomID, limit, offset)
	if err != nil {
		s.logger.Error("failed to get room history",
			zap.Error(err),
			zap.String("room_id", roomID.String()))
		return nil, fmt.Errorf("failed to get room history: %w", err)
	}

	responses := make([]ChatMessageResponse, len(messages))
	for i, msg := range messages {
		responses[i] = ChatMessageResponse{
			ID:             msg.ID,
			ConversationID: msg.ConversationID,
			SenderID:       msg.SenderID,
			Content:        msg.Content,
			MessageType:    msg.MessageType,
			CreatedAt:      msg.CreatedAt,
		}
	}
	return responses, nil
}

