package ru.soune.nocopy.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.file.ActionResponse;
import ru.soune.nocopy.service.notification.NotificationService;
import com.fasterxml.jackson.databind.type.TypeFactory;
import ru.soune.nocopy.dto.notification.*;
import ru.soune.nocopy.entity.notification.Notification;
import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.service.register.AuthService;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Slf4j
@Component
@RequiredArgsConstructor
public class NotificationHandler implements RequestHandler {

    private final NotificationService notificationService;

    private final ObjectMapper objectMapper;

    private final AuthService authService;

    @Override
    public BaseResponse handle(BaseRequest request) throws Exception {
        Map<String, Object> bodyMap = objectMapper.convertValue(request.getMessageBody(),
                TypeFactory.defaultInstance().constructMapType(Map.class, String.class, Object.class));

        String action = (String) bodyMap.get("action");

        if (action == null) {
            ActionResponse response = ActionResponse.builder()
                    .action(action)
                    .availableActions(Arrays.asList("list", "active", "markRead"))
                    .build();

            return new BaseResponse(request.getMsgId(),
                    MessageCode.INVALID_FIELD.getCode(),
                    "Action is required",
                    response);
        }

        switch (action) {
            case "list": {
                NotificationListRequest listRequest = objectMapper.convertValue(request.getMessageBody(),
                        NotificationListRequest.class);
                User user = authService.getUser(listRequest.getAuthToken());

                Page<Notification> page = notificationService.getAllNotifications(
                        user,
                        listRequest.getPage(),
                        listRequest.getSize(),
                        listRequest.getSortBy(),
                        listRequest.getSortDirection(),
                        listRequest.getTypes(),
                        listRequest.getStatuses());

                List<NotificationDto> dtos = page.getContent().stream()
                        .map(this::toDto)
                        .collect(Collectors.toList());

                NotificationListResponse response = NotificationListResponse.builder()
                        .notifications(dtos)
                        .currentPage(page.getNumber())
                        .totalPages(page.getTotalPages())
                        .totalElements(page.getTotalElements())
                        .build();

                return new BaseResponse(request.getMsgId(),
                        MessageCode.SUCCESS.getCode(),
                        MessageCode.SUCCESS.getDescription(),
                        response);
            }

            case "active": {
                ActivateNotificationRequest activateRequest = objectMapper.convertValue(request.getMessageBody(),
                        ActivateNotificationRequest.class);
                User user = authService.getUser(activateRequest.getAuthToken());

                List<Notification> recent = notificationService.getActiveNotifications(user);

                long unreadCount = notificationService.getUnreadCount(user);

                ActiveNotificationsResponse response = ActiveNotificationsResponse.builder()
                        .notifications(recent.stream().map(this::toDto).collect(Collectors.toList()))
                        .unreadCount(unreadCount)
                        .build();

                return new BaseResponse(request.getMsgId(),
                        MessageCode.SUCCESS.getCode(),
                        MessageCode.SUCCESS.getDescription(),
                        response);
            }

            case "markRead": {
                MarkAsReadRequest markRequest = objectMapper.convertValue(request.getMessageBody(),
                        MarkAsReadRequest.class);
                User user = authService.getUser(markRequest.getAuthToken());

                int updated = notificationService.markAsRead(user, markRequest.getNotificationIds());

                MarkAsReadResponse response = MarkAsReadResponse.builder()
                        .success(true)
                        .updatedCount(updated)
                        .build();

                return new BaseResponse(request.getMsgId(),
                        MessageCode.SUCCESS.getCode(),
                        MessageCode.SUCCESS.getDescription(),
                        response);
            }

            case "delete": {
                MarkAsReadRequest markRequest = objectMapper.convertValue(request.getMessageBody(),
                        MarkAsReadRequest.class);

                int delete = notificationService.delete(markRequest.getNotificationIds());

                MarkAsReadResponse response = MarkAsReadResponse.builder()
                        .success(true)
                        .updatedCount(delete)
                        .build();

                return new BaseResponse(request.getMsgId(),
                        MessageCode.SUCCESS.getCode(),
                        MessageCode.SUCCESS.getDescription(),
                        response);
            }

            default:
                ActionResponse response = ActionResponse.builder()
                        .action(action)
                        .availableActions(Arrays.asList("list", "active", "markRead", "delete"))
                        .build();

                return new BaseResponse(request.getMsgId(),
                        MessageCode.INVALID_ACTION.getCode(),
                        "Invalid action: " + action,
                        response);
        }
    }

    private NotificationDto toDto(Notification notification) {
        return NotificationDto.builder()
                .id(notification.getId())
                .message(notification.getMessage())
                .type(notification.getNotificationType())
                .status(notification.getStatus())
                .createdAt(notification.getCreatedAt())
                .build();
    }
}
