package org.raddatz.familienarchiv.notification;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import lombok.RequiredArgsConstructor;
import io.swagger.v3.oas.annotations.Parameter;
import org.raddatz.familienarchiv.notification.NotificationDTO;
import org.raddatz.familienarchiv.notification.NotificationPreferenceDTO;
import org.raddatz.familienarchiv.user.AppUser;
import org.raddatz.familienarchiv.notification.NotificationType;
import org.raddatz.familienarchiv.security.Permission;
import org.raddatz.familienarchiv.security.RequirePermission;
import org.raddatz.familienarchiv.notification.NotificationService;
import org.raddatz.familienarchiv.notification.SseEmitterRegistry;
import org.raddatz.familienarchiv.user.UserService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.util.Map;

import java.util.UUID;

@RestController
@RequiredArgsConstructor
@Validated
public class NotificationController {

    private final NotificationService notificationService;
    private final UserService userService;
    private final SseEmitterRegistry sseEmitterRegistry;

    // These endpoints are intentionally open to any authenticated user —
    // they return and mutate only the current user's own notifications, scoped
    // by the resolved user identity. No additional permission check is required.

    @GetMapping(value = "/api/notifications/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter stream(Authentication authentication) {
        AppUser user = resolveUser(authentication);
        return sseEmitterRegistry.register(user.getId());
    }

    @GetMapping("/api/notifications")
    public Page<NotificationDTO> getNotifications(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") @Min(1) @Max(100) int size,
            @Parameter(description = "Filter by notification type") @RequestParam(required = false) NotificationType type,
            @Parameter(description = "Filter by read status") @RequestParam(required = false) Boolean read,
            Authentication authentication) {
        AppUser user = resolveUser(authentication);
        PageRequest pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
        return notificationService.getNotifications(user.getId(), type, read, pageable);
    }

    @GetMapping("/api/notifications/unread-count")
    public Map<String, Long> countUnread(Authentication authentication) {
        AppUser user = resolveUser(authentication);
        return Map.of("count", notificationService.countUnread(user.getId()));
    }

    @PostMapping("/api/notifications/read-all")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void markAllRead(Authentication authentication) {
        AppUser user = resolveUser(authentication);
        notificationService.markAllRead(user.getId());
    }

    @PatchMapping("/api/notifications/{id}/read")
    public NotificationDTO markOneRead(
            @PathVariable UUID id,
            Authentication authentication) {
        AppUser user = resolveUser(authentication);
        return notificationService.markRead(id, user.getId());
    }

    @GetMapping("/api/users/me/notification-preferences")
    @RequirePermission({Permission.READ_ALL, Permission.WRITE_ALL, Permission.ANNOTATE_ALL})
    public NotificationPreferenceDTO getPreferences(Authentication authentication) {
        AppUser user = resolveUser(authentication);
        return new NotificationPreferenceDTO(user.isNotifyOnReply(), user.isNotifyOnMention());
    }

    @PutMapping("/api/users/me/notification-preferences")
    @RequirePermission({Permission.READ_ALL, Permission.WRITE_ALL, Permission.ANNOTATE_ALL})
    public NotificationPreferenceDTO updatePreferences(
            @RequestBody NotificationPreferenceDTO dto,
            Authentication authentication) {
        AppUser user = resolveUser(authentication);
        AppUser updated = notificationService.updatePreferences(
                user.getId(), dto.notifyOnReply(), dto.notifyOnMention());
        return new NotificationPreferenceDTO(updated.isNotifyOnReply(), updated.isNotifyOnMention());
    }

    // ─── private helpers ──────────────────────────────────────────────────────

    private AppUser resolveUser(Authentication authentication) {
        return userService.findByEmail(authentication.getName());
    }
}
