ClassController.java

package com.wavii.controller;

import com.wavii.model.User;
import com.wavii.service.ChatRealtimeBroadcaster;
import com.wavii.service.ClassService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.util.Map;
import java.util.UUID;

@RestController
@RequestMapping("/api/classes")
@RequiredArgsConstructor
@Slf4j
public class ClassController {

    private final ClassService classService;
    private final ChatRealtimeBroadcaster chatRealtimeBroadcaster;

    /**
     * Lista las clases en las que participa el usuario actual.
     * 
     * @param currentUser Usuario autenticado.
     * @return Listado de clases.
     */
    @GetMapping
    public ResponseEntity<?> listClasses(@AuthenticationPrincipal User currentUser) {
        if (currentUser == null) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                    .body(Map.of("message", "Sesion no valida"));
        }
        try {
            return ResponseEntity.ok(classService.listClasses(currentUser));
        } catch (Exception e) {
            log.warn("Error cargando clases: {}", e.getMessage());
            return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                    .body(Map.of("message", e.getMessage() != null ? e.getMessage() : "No se pudieron cargar las clases"));
        }
    }

    /**
     * Obtiene un resumen de gestión para el profesor o alumno.
     * 
     * @param currentUser Usuario autenticado.
     * @return Resumen de clases y solicitudes.
     */
    @GetMapping("/manage")
    public ResponseEntity<?> manage(@AuthenticationPrincipal User currentUser) {
        if (currentUser == null) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                    .body(Map.of("message", "Sesion no valida"));
        }
        try {
            return ResponseEntity.ok(classService.getManageOverview(currentUser));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("message", e.getMessage()));
        }
    }

    /**
     * Inicia el proceso de pago para contratar a un profesor.
     * 
     * @param teacherId ID del profesor a contratar.
     * @param currentUser Usuario autenticado (alumno).
     * @return Datos para el checkout de Stripe.
     */
    @PostMapping("/{teacherId}/checkout")
    public ResponseEntity<?> checkout(@PathVariable UUID teacherId, @AuthenticationPrincipal User currentUser) {
        try {
            return ResponseEntity.ok(classService.checkout(teacherId, currentUser));
        } catch (Exception e) {
            log.warn("Error preparando pago de clase: {}", e.getMessage());
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("message", e.getMessage()));
        }
    }

    /**
     * Crea una solicitud de clase (tras el pago o reserva).
     * 
     * @param teacherId ID del profesor.
     * @param currentUser Usuario autenticado.
     * @param body Datos de la solicitud.
     * @return La inscripción creada.
     */
    @PostMapping("/{teacherId}/request")
    public ResponseEntity<?> requestClass(@PathVariable UUID teacherId,
                                          @AuthenticationPrincipal User currentUser,
                                          @RequestBody Map<String, String> body) {
        try {
            return ResponseEntity.ok(classService.requestClass(teacherId, currentUser, body));
        } catch (Exception e) {
            log.warn("Error creando solicitud de clase: {}", e.getMessage());
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("message", e.getMessage()));
        }
    }

    /**
     * Confirma una inscripción de clase.
     * 
     * @param enrollmentId ID de la inscripción.
     * @param currentUser Usuario autenticado.
     * @return La inscripción confirmada.
     */
    @PostMapping("/{enrollmentId}/confirm")
    public ResponseEntity<?> confirm(@PathVariable UUID enrollmentId, @AuthenticationPrincipal User currentUser) {
        try {
            return ResponseEntity.ok(classService.confirm(enrollmentId, currentUser));
        } catch (Exception e) {
            log.warn("Error confirmando clase: {}", e.getMessage());
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("message", e.getMessage()));
        }
    }

    /**
     * Obtiene los mensajes del chat de una clase.
     * 
     * @param enrollmentId ID de la inscripción.
     * @param currentUser Usuario autenticado.
     * @return Lista de mensajes.
     */
    @GetMapping("/{enrollmentId}/messages")
    public ResponseEntity<?> messages(@PathVariable UUID enrollmentId, @AuthenticationPrincipal User currentUser) {
        try {
            return ResponseEntity.ok(classService.getMessages(enrollmentId, currentUser));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body(Map.of("message", e.getMessage()));
        }
    }

    /**
     * Envía un mensaje al chat de la clase.
     * 
     * @param enrollmentId ID de la inscripción.
     * @param currentUser Usuario autenticado.
     * @param body Cuerpo con el contenido del mensaje.
     * @return El mensaje enviado.
     */
    @PostMapping("/{enrollmentId}/messages")
    public ResponseEntity<?> sendMessage(@PathVariable UUID enrollmentId,
                                         @AuthenticationPrincipal User currentUser,
                                         @RequestBody Map<String, String> body) {
        try {
            Map<String, Object> saved = classService.sendMessage(enrollmentId, currentUser, body.get("content"));
            chatRealtimeBroadcaster.broadcast(
                    chatRealtimeBroadcaster.classRoom(enrollmentId),
                    saved
            );
            return ResponseEntity.ok(saved);
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("message", e.getMessage()));
        }
    }

    /**
     * Obtiene los posts (muro) de las clases de un profesor.
     * 
     * @param teacherId ID del profesor.
     * @param currentUser Usuario autenticado.
     * @return Lista de posts.
     */
    @GetMapping("/{teacherId}/posts")
    public ResponseEntity<?> posts(@PathVariable UUID teacherId, @AuthenticationPrincipal User currentUser) {
        try {
            return ResponseEntity.ok(classService.getPostsForViewer(currentUser, teacherId));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body(Map.of("message", e.getMessage()));
        }
    }

    /**
     * Obtiene los posts de todos los profesores a los que sigue el alumno.
     * 
     * @param currentUser Usuario autenticado (alumno).
     * @return Lista de posts del tablón del alumno.
     */
    @GetMapping("/posts")
    public ResponseEntity<?> studentPosts(@AuthenticationPrincipal User currentUser) {
        try {
            return ResponseEntity.ok(classService.getPostsForStudent(currentUser));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body(Map.of("message", e.getMessage()));
        }
    }

    /**
     * Crea un post en el muro de clases de un profesor.
     * 
     * @param teacherId ID del profesor.
     * @param currentUser Usuario autenticado.
     * @param body Datos del post (título y contenido).
     * @return El post creado.
     */
    @PostMapping("/{teacherId}/posts")
    public ResponseEntity<?> createPost(@PathVariable UUID teacherId,
                                        @AuthenticationPrincipal User currentUser,
                                        @RequestBody Map<String, String> body) {
        try {
            if (currentUser == null || !currentUser.getId().equals(teacherId)) {
                return ResponseEntity.status(HttpStatus.FORBIDDEN)
                        .body(Map.of("message", "Solo puedes publicar en tus propias clases"));
            }
            return ResponseEntity.ok(classService.createPost(currentUser, body.get("title"), body.get("content")));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("message", e.getMessage()));
        }
    }

    /**
     * Solicita una hora extra para una clase.
     * 
     * @param enrollmentId ID de la inscripción.
     * @param currentUser Usuario autenticado.
     * @return Resultado de la solicitud.
     */
    @PostMapping("/{enrollmentId}/request-extra-hour")
    public ResponseEntity<?> requestExtraHour(@PathVariable UUID enrollmentId,
                                              @AuthenticationPrincipal User currentUser) {
        try {
            return ResponseEntity.ok(classService.requestExtraHour(enrollmentId, currentUser));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("message", e.getMessage()));
        }
    }

    /**
     * Solicita un reembolso para una clase.
     * 
     * @param enrollmentId ID de la inscripción.
     * @param currentUser Usuario autenticado.
     * @return Resultado de la solicitud.
     */
    @PostMapping("/{enrollmentId}/refund-request")
    public ResponseEntity<?> requestRefund(@PathVariable UUID enrollmentId,
                                           @AuthenticationPrincipal User currentUser) {
        try {
            return ResponseEntity.ok(classService.requestRefund(enrollmentId, currentUser));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("message", e.getMessage()));
        }
    }

    /**
     * Actualiza el estado de una inscripción.
     * 
     * @param enrollmentId ID de la inscripción.
     * @param currentUser Usuario autenticado.
     * @param body Mapa con el nuevo estado.
     * @return La inscripción actualizada.
     */
    @PatchMapping("/{enrollmentId}/status")
    public ResponseEntity<?> updateStatus(@PathVariable UUID enrollmentId,
                                          @AuthenticationPrincipal User currentUser,
                                          @RequestBody Map<String, String> body) {
        try {
            return ResponseEntity.ok(classService.updateStatus(enrollmentId, currentUser, body));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("message", e.getMessage()));
        }
    }

    /**
     * Crea una sesión programada para una clase.
     * 
     * @param enrollmentId ID de la inscripción.
     * @param currentUser Usuario autenticado.
     * @param body Datos de la sesión.
     * @return La sesión creada.
     */
    @PostMapping("/{enrollmentId}/sessions")
    public ResponseEntity<?> createSession(@PathVariable UUID enrollmentId,
                                           @AuthenticationPrincipal User currentUser,
                                           @RequestBody Map<String, String> body) {
        try {
            return ResponseEntity.ok(classService.createSession(enrollmentId, currentUser, body));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("message", e.getMessage()));
        }
    }

    /**
     * Actualiza una sesión programada.
     * 
     * @param sessionId ID de la sesión.
     * @param currentUser Usuario autenticado.
     * @param body Datos a actualizar.
     * @return La sesión actualizada.
     */
    @PatchMapping("/sessions/{sessionId}")
    public ResponseEntity<?> updateSession(@PathVariable UUID sessionId,
                                           @AuthenticationPrincipal User currentUser,
                                           @RequestBody Map<String, String> body) {
        try {
            return ResponseEntity.ok(classService.updateSession(sessionId, currentUser, body));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("message", e.getMessage()));
        }
    }
}