ModerationController.java

package com.wavii.controller;

import com.wavii.model.BandListing;
import com.wavii.model.User;
import com.wavii.repository.BandListingRepository;
import com.wavii.repository.UserRepository;
import com.wavii.service.NotificationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

@RestController
@RequestMapping("/api/moderation")
@RequiredArgsConstructor
@Slf4j
public class ModerationController {

    private final BandListingRepository bandListingRepository;
    private final UserRepository userRepository;
    private final NotificationService notificationService;

    @Value("${odoo.webhook-secret:}")
    private String odooWebhookSecret;

    @PostMapping("/odoo-webhook")
    public ResponseEntity<?> odooWebhook(
            @RequestHeader(value = "X-Odoo-Secret", required = false) String receivedSecret,
            @RequestBody Map<String, String> body
    ) {
        if (odooWebhookSecret == null || odooWebhookSecret.isBlank()
                || !odooWebhookSecret.equals(receivedSecret)) {
            log.warn("Odoo moderation webhook: secreto invalido o ausente");
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Map.of("message", "Secreto no valido"));
        }

        String action = body.get("action");
        String reportType = body.get("reportType");
        String targetReference = body.get("targetReference");
        String reporterEmail = body.get("reporterEmail");

        if (action == null || reportType == null || targetReference == null) {
            return ResponseEntity.badRequest().body(Map.of("message", "Se requieren action, reportType y targetReference"));
        }

        if (!"band_listing".equals(reportType)) {
            notifyReporter(reporterEmail, action, null);
            return ResponseEntity.ok(Map.of("message", "Reporte actualizado"));
        }

        UUID listingId = parseBandListingReference(targetReference);
        if (listingId == null) {
            return ResponseEntity.badRequest().body(Map.of("message", "Referencia de anuncio invalida"));
        }

        BandListing listing = bandListingRepository.findById(listingId).orElse(null);
        if (listing == null) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of("message", "Anuncio no encontrado"));
        }

        String normalizedAction = action.toLowerCase(Locale.ROOT);
        if ("approve".equals(normalizedAction)) {
            listing.setRemovedByModeration(true);
            listing.setRemovedAt(LocalDateTime.now());
            bandListingRepository.save(listing);
            notifyListingCreator(listing);
            notifyReporter(reporterEmail, "approve", listing);
            return ResponseEntity.ok(Map.of("message", "Reporte aprobado y anuncio eliminado"));
        }
        if ("reject".equals(normalizedAction)) {
            notifyReporter(reporterEmail, "reject", listing);
            return ResponseEntity.ok(Map.of("message", "Reporte rechazado"));
        }

        return ResponseEntity.badRequest().body(Map.of("message", "Accion no valida. Usa approve o reject"));
    }

    private UUID parseBandListingReference(String targetReference) {
        if (!targetReference.startsWith("band_listing:")) {
            return null;
        }
        try {
            return UUID.fromString(targetReference.substring("band_listing:".length()));
        } catch (IllegalArgumentException e) {
            return null;
        }
    }

    private void notifyListingCreator(BandListing listing) {
        notificationService.create(
                listing.getCreator(),
                "moderation_listing_removed",
                "Anuncio eliminado",
                "Tu anuncio \"" + listing.getTitle() + "\" ha sido eliminado tras revisar un reporte.",
                Map.of("listingId", listing.getId().toString())
        );
    }

    private void notifyReporter(String reporterEmail, String action, BandListing listing) {
        if (reporterEmail == null || reporterEmail.isBlank()) {
            return;
        }
        Optional<User> reporter = userRepository.findByEmail(reporterEmail);
        if (reporter.isEmpty()) {
            return;
        }
        boolean approved = "approve".equalsIgnoreCase(action);
        String title = approved ? "Reporte aprobado" : "Reporte rechazado";
        String body = approved
                ? "Hemos revisado tu reporte y se ha tomado accion."
                : "Hemos revisado tu reporte y no se ha tomado accion sobre el contenido.";
        Map<String, Object> data = listing != null
                ? Map.of("listingId", listing.getId().toString())
                : Map.of();
        notificationService.create(reporter.get(), approved ? "moderation_report_approved" : "moderation_report_rejected", title, body, data);
    }
}