package controller

import (
	"narasi-ahli-be/app/module/chat/request"
	"narasi-ahli-be/app/module/chat/service"
	"narasi-ahli-be/utils/paginator"
	utilRes "narasi-ahli-be/utils/response"
	utilVal "narasi-ahli-be/utils/validator"
	"strconv"

	"github.com/gofiber/fiber/v2"
)

type chatController struct {
	chatService service.ChatService
}

type ChatController interface {
	// Chat Session endpoints
	GetAllChatSessions(c *fiber.Ctx) error
	GetChatSessionByID(c *fiber.Ctx) error
	CreateChatSession(c *fiber.Ctx) error
	UpdateChatSession(c *fiber.Ctx) error
	DeleteChatSession(c *fiber.Ctx) error

	// Chat Message endpoints
	GetAllChatMessages(c *fiber.Ctx) error
	GetChatMessageByID(c *fiber.Ctx) error
	CreateChatMessage(c *fiber.Ctx) error
	UpdateChatMessage(c *fiber.Ctx) error
	DeleteChatMessage(c *fiber.Ctx) error

	// Chat Participant endpoints
	AddParticipantToChat(c *fiber.Ctx) error
	RemoveParticipantFromChat(c *fiber.Ctx) error
}

func NewChatController(chatService service.ChatService) ChatController {
	return &chatController{
		chatService: chatService,
	}
}

// GetAllChatSessions - Get all chat sessions for a user
// @Summary      Get all chat sessions
// @Description  API for getting all chat sessions for authenticated user
// @Tags         Chat
// @Security     Bearer
// @Param        Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
// @Param        type query string false "Chat type (personal or group)"
// @Param        req query paginator.Pagination false "pagination parameters"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /chat/sessions [get]
func (_i *chatController) GetAllChatSessions(c *fiber.Ctx) error {
	paginate, err := paginator.Paginate(c)
	if err != nil {
		return err
	}

	authToken := c.Get("Authorization")

	reqContext := request.ChatSessionQueryRequestContext{
		Type: c.Query("type"),
	}
	req := reqContext.ToParamRequest()
	req.Pagination = paginate

	chatSessions, paging, err := _i.chatService.GetAllChatSessions(authToken, req)
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Chat sessions successfully retrieved"},
		Data:     chatSessions,
		Meta:     paging,
	})
}

// GetChatSessionByID - Get one chat session
// @Summary      Get one chat session
// @Description  API for getting one chat session
// @Tags         Chat
// @Security     Bearer
// @Param        Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
// @Param        id path int true "Chat Session ID"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /chat/sessions/{id} [get]
func (_i *chatController) GetChatSessionByID(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 0)
	if err != nil {
		return err
	}

	authToken := c.Get("Authorization")

	chatSession, err := _i.chatService.GetChatSessionByID(authToken, uint(id))
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Chat session successfully retrieved"},
		Data:     chatSession,
	})
}

// CreateChatSession - Create chat session
// @Summary      Create chat session
// @Description  API for creating a new chat session (personal or group)
// @Tags         Chat
// @Security     Bearer
// @Param        X-Csrf-Token header string true "Insert the X-Csrf-Token"
// @Param        Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
// @Param        payload body request.ChatSessionCreateRequest true "Required payload"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /chat/sessions [post]
func (_i *chatController) CreateChatSession(c *fiber.Ctx) error {
	authToken := c.Get("Authorization")

	req := new(request.ChatSessionCreateRequest)
	if err := utilVal.ParseAndValidate(c, req); err != nil {
		return err
	}

	dataResult, err := _i.chatService.CreateChatSession(authToken, *req)
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Chat session successfully created"},
		Data:     dataResult,
	})
}

// UpdateChatSession - Update chat session
// @Summary      Update chat session
// @Description  API for updating chat session (only creator can update)
// @Tags         Chat
// @Security     Bearer
// @Param        X-Csrf-Token header string true "Insert the X-Csrf-Token"
// @Param        Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
// @Param        id path int true "Chat Session ID"
// @Param        payload body request.ChatSessionUpdateRequest true "Required payload"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /chat/sessions/{id} [put]
func (_i *chatController) UpdateChatSession(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 0)
	if err != nil {
		return err
	}

	authToken := c.Get("Authorization")

	req := new(request.ChatSessionUpdateRequest)
	if err := utilVal.ParseAndValidate(c, req); err != nil {
		return err
	}

	err = _i.chatService.UpdateChatSession(authToken, uint(id), *req)
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Chat session successfully updated"},
	})
}

// DeleteChatSession - Delete chat session
// @Summary      Delete chat session
// @Description  API for deleting chat session (only creator can delete)
// @Tags         Chat
// @Security     Bearer
// @Param        X-Csrf-Token header string true "Insert the X-Csrf-Token"
// @Param        Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
// @Param        id path int true "Chat Session ID"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /chat/sessions/{id} [delete]
func (_i *chatController) DeleteChatSession(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 0)
	if err != nil {
		return err
	}

	authToken := c.Get("Authorization")

	err = _i.chatService.DeleteChatSession(authToken, uint(id))
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Chat session successfully deleted"},
	})
}

// GetAllChatMessages - Get all messages in a chat session
// @Summary      Get all chat messages
// @Description  API for getting all messages in a specific chat session
// @Tags         Chat
// @Security     Bearer
// @Param        Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
// @Param        chatSessionId query uint true "Chat Session ID"
// @Param        req query paginator.Pagination false "pagination parameters"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /chat/messages [get]
func (_i *chatController) GetAllChatMessages(c *fiber.Ctx) error {
	paginate, err := paginator.Paginate(c)
	if err != nil {
		return err
	}

	authToken := c.Get("Authorization")

	reqContext := request.ChatMessageQueryRequestContext{
		ChatSessionID: c.Query("chatSessionId"),
	}
	req := reqContext.ToParamRequest()
	req.Pagination = paginate

	chatMessages, paging, err := _i.chatService.GetAllChatMessages(authToken, req)
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Chat messages successfully retrieved"},
		Data:     chatMessages,
		Meta:     paging,
	})
}

// GetChatMessageByID - Get one chat message
// @Summary      Get one chat message
// @Description  API for getting one chat message
// @Tags         Chat
// @Security     Bearer
// @Param        Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
// @Param        id path int true "Chat Message ID"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /chat/messages/{id} [get]
func (_i *chatController) GetChatMessageByID(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 0)
	if err != nil {
		return err
	}

	authToken := c.Get("Authorization")

	chatMessage, err := _i.chatService.GetChatMessageByID(authToken, uint(id))
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Chat message successfully retrieved"},
		Data:     chatMessage,
	})
}

// CreateChatMessage - Create chat message
// @Summary      Create chat message
// @Description  API for creating a new chat message
// @Tags         Chat
// @Security     Bearer
// @Param        X-Csrf-Token header string true "Insert the X-Csrf-Token"
// @Param        Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
// @Param        payload body request.ChatMessageCreateRequest true "Required payload"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /chat/messages [post]
func (_i *chatController) CreateChatMessage(c *fiber.Ctx) error {
	authToken := c.Get("Authorization")

	req := new(request.ChatMessageCreateRequest)
	if err := utilVal.ParseAndValidate(c, req); err != nil {
		return err
	}

	dataResult, err := _i.chatService.CreateChatMessage(authToken, *req)
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Chat message successfully created"},
		Data:     dataResult,
	})
}

// UpdateChatMessage - Update chat message
// @Summary      Update chat message
// @Description  API for updating chat message (only sender can update)
// @Tags         Chat
// @Security     Bearer
// @Param        X-Csrf-Token header string true "Insert the X-Csrf-Token"
// @Param        Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
// @Param        id path int true "Chat Message ID"
// @Param        payload body request.ChatMessageUpdateRequest true "Required payload"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /chat/messages/{id} [put]
func (_i *chatController) UpdateChatMessage(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 0)
	if err != nil {
		return err
	}

	authToken := c.Get("Authorization")

	req := new(request.ChatMessageUpdateRequest)
	if err := utilVal.ParseAndValidate(c, req); err != nil {
		return err
	}

	err = _i.chatService.UpdateChatMessage(authToken, uint(id), *req)
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Chat message successfully updated"},
	})
}

// DeleteChatMessage - Delete chat message
// @Summary      Delete chat message
// @Description  API for deleting chat message (only sender can delete)
// @Tags         Chat
// @Security     Bearer
// @Param        X-Csrf-Token header string true "Insert the X-Csrf-Token"
// @Param        Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
// @Param        id path int true "Chat Message ID"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /chat/messages/{id} [delete]
func (_i *chatController) DeleteChatMessage(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 0)
	if err != nil {
		return err
	}

	authToken := c.Get("Authorization")

	err = _i.chatService.DeleteChatMessage(authToken, uint(id))
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Chat message successfully deleted"},
	})
}

// AddParticipantToChat - Add participant to chat session
// @Summary      Add participant to chat session
// @Description  API for adding a participant to a chat session (only creator can add)
// @Tags         Chat
// @Security     Bearer
// @Param        X-Csrf-Token header string true "Insert the X-Csrf-Token"
// @Param        Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
// @Param        chatSessionId path int true "Chat Session ID"
// @Param        participantUserId query uint true "Participant User ID"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /chat/sessions/{chatSessionId}/participants [post]
func (_i *chatController) AddParticipantToChat(c *fiber.Ctx) error {
	chatSessionId, err := strconv.ParseUint(c.Params("chatSessionId"), 10, 0)
	if err != nil {
		return err
	}

	authToken := c.Get("Authorization")

	participantUserId, err := strconv.ParseUint(c.Query("participantUserId"), 10, 0)
	if err != nil {
		return utilRes.Resp(c, utilRes.Response{
			Success:  false,
			Messages: utilRes.Messages{"participantUserId parameter is required and must be a valid number"},
		})
	}

	err = _i.chatService.AddParticipantToChat(authToken, uint(chatSessionId), uint(participantUserId))
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Participant successfully added to chat session"},
	})
}

// RemoveParticipantFromChat - Remove participant from chat session
// @Summary      Remove participant from chat session
// @Description  API for removing a participant from a chat session (creator can remove anyone, user can remove themselves)
// @Tags         Chat
// @Security     Bearer
// @Param        X-Csrf-Token header string true "Insert the X-Csrf-Token"
// @Param        Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
// @Param        chatSessionId path int true "Chat Session ID"
// @Param        participantUserId query uint true "Participant User ID"
// @Success      200  {object}  response.Response
// @Failure      400  {object}  response.BadRequestError
// @Failure      401  {object}  response.UnauthorizedError
// @Failure      500  {object}  response.InternalServerError
// @Router       /chat/sessions/{chatSessionId}/participants [delete]
func (_i *chatController) RemoveParticipantFromChat(c *fiber.Ctx) error {
	chatSessionId, err := strconv.ParseUint(c.Params("chatSessionId"), 10, 0)
	if err != nil {
		return err
	}

	authToken := c.Get("Authorization")

	participantUserId, err := strconv.ParseUint(c.Query("participantUserId"), 10, 0)
	if err != nil {
		return utilRes.Resp(c, utilRes.Response{
			Success:  false,
			Messages: utilRes.Messages{"participantUserId parameter is required and must be a valid number"},
		})
	}

	err = _i.chatService.RemoveParticipantFromChat(authToken, uint(chatSessionId), uint(participantUserId))
	if err != nil {
		return err
	}

	return utilRes.Resp(c, utilRes.Response{
		Success:  true,
		Messages: utilRes.Messages{"Participant successfully removed from chat session"},
	})
}
