PULSOFT

2.JPA Relaciones

1.Cita

1. Cita
Crear un sistema de gestión de citas médicas donde se permita registrar citas entre pacientes y médicos.
Cada cita debe contener fecha, motivo de la consulta y relación con un paciente y un médico.
El sistema debe implementar arquitectura Controller - Service - Repository usando Spring Boot y JPA.

package es.pulsoft.spring_hospital.controller;

import es.pulsoft.spring_hospital.model.Cita;
import es.pulsoft.spring_hospital.model.enums.EstadoCita;
import es.pulsoft.spring_hospital.service.CitaService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.util.List;

// Controlador REST encargado de gestionar las operaciones relacionadas con Cita
@RestController
@RequestMapping("/citas")
public class CitaController {

    // Servicio que contiene la lógica de negocio de citas
    private final CitaService citaService;

    // Inyección del servicio de citas
    public CitaController(CitaService citaService) {
        this.citaService = citaService;
    }

    // Obtiene listado de citas con filtros opcionales
    // Permite filtrar por motivo, estado y rango de fechas
    @GetMapping
    public List<Cita> listarCitas(
            @RequestParam(required = false) String motivo,
            @RequestParam(required = false) EstadoCita estado,
            @RequestParam(required = false) LocalDate inicio,
            @RequestParam(required = false) LocalDate fin) {

        return citaService.listarCitas(motivo, estado, inicio, fin);
    }

    // Obtiene una cita por su identificador
    @GetMapping("/{id}")
    public Cita buscarPorId(@PathVariable Long id) {
        return citaService.buscarPorId(id);
    }

    // Crea una nueva cita en el sistema
    @PostMapping
    public Cita crearCita(@RequestBody Cita cita) {
        return citaService.crearCita(cita);
    }

    // Actualiza completamente una cita existente
    // Reemplaza todos los campos de la entidad
    @PutMapping("/{id}")
    public ResponseEntity<Cita> actualizarCita(
            @PathVariable Long id,
            @RequestBody Cita cita) {

        return citaService.actualizarCita(id, cita);
    }

    // Elimina una cita por su identificador
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> borrarCita(@PathVariable Long id) {
        return citaService.borrarCita(id);
    }

    // Actualización parcial de una cita
    // Solo modifica los campos enviados en la petición
    @PatchMapping("/{id}")
    public ResponseEntity<Cita> actualizacionParcial(
            @PathVariable Long id,
            @RequestBody Cita cita) {

        return citaService.actualizacionParcial(id, cita);
    }
}
package es.pulsoft.spring_hospital.model;

import es.pulsoft.spring_hospital.model.enums.EstadoCita;
import jakarta.persistence.*;

import java.time.LocalDate;

// Entidad JPA que representa una cita médica en el sistema
@Entity
@Table(name="cita")
public class Cita {

    // Identificador único de la cita en base de datos
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // Fecha en la que se realiza la cita
    private LocalDate fecha;

    // Motivo o descripción de la cita médica
    private String motivo;

    // Estado actual de la cita (PENDIENTE, CONFIRMADA, etc.)
    @Enumerated(EnumType.STRING)
    private EstadoCita estado;

    // Relación ManyToOne: muchas citas pueden pertenecer a un mismo paciente
    @ManyToOne
    @JoinColumn(name="paciente_id")
    private Paciente paciente;

    // Relación ManyToOne: muchas citas pueden estar asignadas al mismo médico
    @ManyToOne
    @JoinColumn(name="medico_id")
    private Medico medico;

    // Constructor vacío requerido por JPA
    public Cita(){

    }

    // Constructor para crear una cita con datos básicos
    // La fecha se asigna automáticamente a la fecha actual
    public Cita(String motivo, EstadoCita estado, Paciente paciente, Medico medico) {
        this.fecha = LocalDate.now();
        this.motivo = motivo;
        this.estado = estado;
        this.paciente = paciente;
        this.medico = medico;
    }

    // Obtiene el identificador de la cita
    public Long getId() {
        return id;
    }

    // Obtiene la fecha de la cita
    public LocalDate getFecha() {
        return fecha;
    }

    // Establece la fecha de la cita
    public void setFecha(LocalDate fecha) {
        this.fecha = fecha;
    }

    // Obtiene el motivo de la cita
    public String getMotivo() {
        return motivo;
    }

    // Establece el motivo de la cita
    public void setMotivo(String motivo) {
        this.motivo = motivo;
    }

    // Obtiene el estado actual de la cita
    public EstadoCita getEstado() {
        return estado;
    }

    // Establece el estado de la cita
    public void setEstado(EstadoCita estado) {
        this.estado = estado;
    }

    // Obtiene el paciente asociado a la cita
    public Paciente getPaciente() {
        return paciente;
    }

    // Asigna un paciente a la cita
    public void setPaciente(Paciente paciente) {
        this.paciente = paciente;
    }

    // Obtiene el médico asignado a la cita
    public Medico getMedico() {
        return medico;
    }

    // Asigna un médico a la cita
    public void setMedico(Medico medico) {
        this.medico = medico;
    }
}
package es.pulsoft.spring_hospital.repository;

import es.pulsoft.spring_hospital.model.Cita;
import es.pulsoft.spring_hospital.model.enums.EstadoCita;
import org.springframework.data.jpa.repository.JpaRepository;

import java.time.LocalDate;
import java.util.List;

// Repositorio de acceso a datos para la entidad Cita
// Extiende JpaRepository para operaciones CRUD automáticas
public interface CitaRepository extends JpaRepository<Cita, Long> {

    // Busca citas cuyo motivo contenga el texto indicado (ignore case)
    List<Cita> findByMotivoContainingIgnoreCase(String motivo);

    // Filtra citas por estado (PENDIENTE, CONFIRMADA, etc.)
    List<Cita> findByEstado(EstadoCita estado);

    // Filtra por motivo y estado a la vez
    List<Cita> findByMotivoContainingIgnoreCaseAndEstado(String motivo, EstadoCita estado);

    // Obtiene citas dentro de un rango de fechas
    List<Cita> findByFechaBetween(LocalDate inicio, LocalDate fin);

    // Busca citas por fecha exacta
    List<Cita> findByFecha(LocalDate inicio);
}
package es.pulsoft.spring_hospital.service;

import es.pulsoft.spring_hospital.model.Cita;
import es.pulsoft.spring_hospital.model.Medico;
import es.pulsoft.spring_hospital.model.Paciente;
import es.pulsoft.spring_hospital.model.enums.EstadoCita;
import es.pulsoft.spring_hospital.repository.CitaRepository;
import es.pulsoft.spring_hospital.repository.MedicoRepository;
import es.pulsoft.spring_hospital.repository.PacienteRepository;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

import java.time.LocalDate;
import java.util.List;

@Service
public class CitaService {

    // Repositorio de citas
    private final CitaRepository citaRepository;

    // Repositorio de pacientes
    private final PacienteRepository pacienteRepository;

    // Repositorio de médicos
    private final MedicoRepository medicoRepository;

    // Constructor con inyección de dependencias
    public CitaService(CitaRepository citaRepository,
                       PacienteRepository pacienteRepository,
                       MedicoRepository medicoRepository) {

        this.citaRepository = citaRepository;
        this.pacienteRepository = pacienteRepository;
        this.medicoRepository = medicoRepository;
    }

    // Listado de citas con filtros opcionales
    public List<Cita> listarCitas(String motivo,
                                  EstadoCita estado,
                                  LocalDate inicio,
                                  LocalDate fin) {

        if (inicio != null && fin != null) {
            return citaRepository.findByFechaBetween(inicio, fin);
        }

        if (motivo != null && estado != null) {
            return citaRepository.findByMotivoContainingIgnoreCaseAndEstado(motivo, estado);
        }

        if (motivo != null) {
            return citaRepository.findByMotivoContainingIgnoreCase(motivo);
        }

        if (estado != null) {
            return citaRepository.findByEstado(estado);
        }

        if (inicio != null) {
            return citaRepository.findByFecha(inicio);
        }

        return citaRepository.findAll();
    }

    // Buscar cita por ID
    public Cita buscarPorId(Long id) {
        return citaRepository.findById(id)
                .orElseThrow(() -> new ResponseStatusException(
                        HttpStatus.NOT_FOUND,
                        "Cita no encontrada"));
    }

    // Crear cita
    public Cita crearCita(Cita cita) {

        validaciones(cita);

        return citaRepository.save(cita);
    }

    // Actualizar cita completa
    public ResponseEntity<Cita> actualizarCita(Long id, Cita cita) {

        Cita c = buscarPorId(id);

        validaciones(cita);

        c.setFecha(cita.getFecha());
        c.setEstado(cita.getEstado());
        c.setMotivo(cita.getMotivo());
        c.setMedico(cita.getMedico());
        c.setPaciente(cita.getPaciente());

        return ResponseEntity.ok(citaRepository.save(c));
    }

    // Eliminar cita
    public ResponseEntity<Void> borrarCita(Long id) {

        Cita c = buscarPorId(id);

        citaRepository.delete(c);

        return ResponseEntity.noContent().build();
    }

    // Validaciones de negocio
    private void validaciones(Cita cita) {

        if (cita.getMotivo() == null) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "El motivo de la cita no puede quedar sin rellenar.");
        }

        if (cita.getEstado() == null) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "El estado de la cita no puede quedar sin rellenar.");
        }

        if (cita.getFecha() == null) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "La fecha de la cita no puede quedar sin rellenar.");
        }

        Paciente p = pacienteRepository.findById(cita.getPaciente().getId())
                .orElseThrow(() -> new ResponseStatusException(
                        HttpStatus.NOT_FOUND,
                        "Paciente no encontrado"));

        Medico m = medicoRepository.findById(cita.getMedico().getId())
                .orElseThrow(() -> new ResponseStatusException(
                        HttpStatus.NOT_FOUND,
                        "Médico no encontrado"));

        cita.setPaciente(p);
        cita.setMedico(m);
    }

    // Actualización parcial
    public ResponseEntity<Cita> actualizacionParcial(Long id, Cita cita) {

        Cita c = citaRepository.findById(id)
                .orElseThrow(() -> new ResponseStatusException(
                        HttpStatus.NOT_FOUND,
                        "La cita no existe"));

        if (cita.getFecha() != null) {
            if (cita.getFecha().isBefore(LocalDate.now())) {
                throw new ResponseStatusException(
                        HttpStatus.BAD_REQUEST,
                        "La fecha debe ser hoy o futura");
            }
            c.setFecha(cita.getFecha());
        }

        if (cita.getMotivo() != null) {
            c.setMotivo(cita.getMotivo());
        }

        if (cita.getEstado() != null) {
            c.setEstado(cita.getEstado());
        }

        if (cita.getPaciente() != null && cita.getPaciente().getId() != null) {

            Paciente p = pacienteRepository.findById(cita.getPaciente().getId())
                    .orElseThrow(() -> new ResponseStatusException(
                            HttpStatus.NOT_FOUND,
                            "Paciente no encontrado"));

            c.setPaciente(p);
        }

        if (cita.getMedico() != null && cita.getMedico().getId() != null) {

            Medico m = medicoRepository.findById(cita.getMedico().getId())
                    .orElseThrow(() -> new ResponseStatusException(
                            HttpStatus.NOT_FOUND,
                            "Médico no encontrado"));

            c.setMedico(m);
        }

        return ResponseEntity.ok(citaRepository.save(c));
    }
}
2.Departamento

2. Departamento
Desarrollar una API REST para la gestión de departamentos de un hospital.
Cada departamento tendrá un nombre, ubicación y relación con los médicos que pertenecen a él.
Se debe permitir el CRUD completo utilizando Spring Boot con arquitectura en capas.

package es.pulsoft.spring_hospital.controller;

import es.pulsoft.spring_hospital.model.Departamento;
import es.pulsoft.spring_hospital.service.DepartamentoService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/departamentos")
public class DepartamentoController {

    // Servicio de departamentos
    private final DepartamentoService departamentoService;

    // Constructor con inyección de dependencias
    public DepartamentoController(DepartamentoService departamentoService) {
        this.departamentoService = departamentoService;
    }

    // Lista departamentos con filtro opcional por nombre
    @GetMapping
    public List<Departamento> filtrar(
            @RequestParam(required = false) String nombre) {

        return departamentoService.filtrar(nombre);
    }

    // Busca departamento por ID
    @GetMapping("/{id}")
    public Departamento buscarPorId(@PathVariable Long id) {
        return departamentoService.buscarPorId(id);
    }

    // Crea un nuevo departamento
    @PostMapping
    public Departamento crearDepartamento(@RequestBody Departamento departamento) {
        return departamentoService.crearDepartamento(departamento);
    }

    // Actualiza completamente un departamento existente
    @PutMapping("/{id}")
    public ResponseEntity<Departamento> actualizarDepartamento(
            @PathVariable Long id,
            @RequestBody Departamento departamento) {

        return departamentoService.actualizarDepartamento(id, departamento);
    }

    // Elimina un departamento por ID
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> borrarDepartamento(@PathVariable Long id) {
        return departamentoService.borrarDepartamento(id);
    }

    // Actualización parcial del departamento
    @PatchMapping("/{id}")
    public ResponseEntity<Departamento> actualizacionParcial(
            @PathVariable Long id,
            @RequestBody Departamento departamento) {

        return departamentoService.actualizacionParcial(id, departamento);
    }
}
package es.pulsoft.spring_hospital.model;

import jakarta.persistence.*;

import java.util.List;

// Entidad que representa un departamento dentro del hospital
@Entity
@Table(name = "departamento")
public class Departamento {

    // Identificador único del departamento
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // Nombre del departamento (ej: Cardiología, Traumatología, etc.)
    private String nombre;

    // Relación OneToMany: un departamento puede tener muchos médicos
    // mappedBy indica que la relación está gestionada desde la entidad Medico
    @OneToMany(mappedBy = "departamento")
    private List<Medico> medicos;

    // Constructor vacío requerido por JPA
    public Departamento() {

    }

    // Constructor para crear un departamento con sus datos básicos
    public Departamento(String nombre, List<Medico> medicos) {
        this.nombre = nombre;
        this.medicos = medicos;
    }

    // Obtiene el identificador del departamento
    public Long getId() {
        return id;
    }

    // Obtiene el nombre del departamento
    public String getNombre() {
        return nombre;
    }

    // Establece el nombre del departamento
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    // Obtiene la lista de médicos del departamento
    public List<Medico> getMedicos() {
        return medicos;
    }

    // Asigna la lista de médicos al departamento
    public void setMedicos(List<Medico> medicos) {
        this.medicos = medicos;
    }
}
package es.pulsoft.spring_hospital.repository;

import es.pulsoft.spring_hospital.model.Departamento;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

// Repositorio de acceso a datos para la entidad Departamento
// Proporciona operaciones CRUD básicas mediante JpaRepository
public interface DepartamentoRepository extends JpaRepository<Departamento, Long> {

    // Busca departamentos cuyo nombre contenga el texto indicado (ignore case)
    List<Departamento> findByNombreContainingIgnoreCase(String nombre);
}
package es.pulsoft.spring_hospital.service;

import es.pulsoft.spring_hospital.model.Departamento;
import es.pulsoft.spring_hospital.repository.DepartamentoRepository;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

import java.util.List;

@Service
public class DepartamentoService {

    private final DepartamentoRepository departamentoRepository;

    // Inyección del repositorio de departamentos
    public DepartamentoService(DepartamentoRepository departamentoRepository) {
        this.departamentoRepository = departamentoRepository;
    }

    // Filtra departamentos por nombre (búsqueda parcial, case insensitive)
    // Si no se proporciona nombre, devuelve todos los registros
    public List<Departamento> filtrar(String nombre) {

        if (nombre == null) {
            return departamentoRepository.findAll();
        } else {
            return departamentoRepository.findByNombreContainingIgnoreCase(nombre);
        }
    }

    // Busca un departamento por su identificador
    // Lanza excepción 404 si no existe
    public Departamento buscarPorId(Long id) {
        return departamentoRepository.findById(id).orElseThrow(() ->
                new ResponseStatusException(HttpStatus.NOT_FOUND,
                        "Departamento no encontrado"));
    }

    // Crea un nuevo departamento aplicando validaciones de negocio
    public Departamento crearDepartamento(Departamento departamento) {

        validaciones(departamento);

        return departamentoRepository.save(departamento);
    }

    // Actualiza completamente un departamento existente
    public ResponseEntity<Departamento> actualizarDepartamento(Long id, Departamento departamento) {

        Departamento d = buscarPorId(id);

        d.setNombre(departamento.getNombre());

        return ResponseEntity.ok(departamentoRepository.save(d));
    }

    // Elimina un departamento por su identificador
    public ResponseEntity<Void> borrarDepartamento(Long id) {

        Departamento d = buscarPorId(id);

        departamentoRepository.delete(d);

        return ResponseEntity.noContent().build();
    }

    // Validaciones de negocio para creación de departamentos
    // Verifica que el nombre no sea nulo ni vacío
    private void validaciones(Departamento departamento) {

        if (departamento.getNombre() == null || departamento.getNombre().trim().isEmpty()) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "El nombre del departamento no puede quedar sin rellenar.");
        }
    }

    // Actualización parcial de un departamento
    // Solo modifica los campos enviados en la petición
    public ResponseEntity<Departamento> actualizacionParcial(Long id, Departamento departamento) {

        Departamento d = departamentoRepository.findById(id)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND,
                        "Departamento no encontrado"));

        if (departamento.getNombre() != null) {
            d.setNombre(departamento.getNombre());
        }

        return ResponseEntity.ok(departamentoRepository.save(d));
    }
}
3.HistoriaClinica

3. HistoriaClinica
Implementar un sistema de historias clínicas asociadas a pacientes.
Cada historia clínica debe contener diagnósticos, observaciones y estar vinculada a un único paciente.
Se debe usar relación uno a uno con JPA y estructura Controller - Service - Repository.

package es.pulsoft.spring_hospital.controller;

import es.pulsoft.spring_hospital.model.HistoriaClinica;
import es.pulsoft.spring_hospital.service.HistoriaClinicaService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.util.List;

@RestController
@RequestMapping("/historias")
public class HistoriaClinicaController {

    // Servicio de historias clínicas
    private final HistoriaClinicaService historiaClinicaService;

    // Inyección del servicio
    public HistoriaClinicaController(HistoriaClinicaService historiaClinicaService) {
        this.historiaClinicaService = historiaClinicaService;
    }

    // Listado con filtros opcionales
    @GetMapping
    public List<HistoriaClinica> filtrar(
            @RequestParam(required = false) String descripcion,
            @RequestParam(required = false) LocalDate inicio,
            @RequestParam(required = false) LocalDate fin) {

        return historiaClinicaService.filtrar(descripcion, inicio, fin);
    }

    // Buscar por ID
    @GetMapping("/{id}")
    public HistoriaClinica buscarPorId(@PathVariable Long id) {
        return historiaClinicaService.buscarPorId(id);
    }

    // Crear historia clínica
    @PostMapping
    public HistoriaClinica crearHistoria(@RequestBody HistoriaClinica historiaClinica) {
        return historiaClinicaService.crearHistoria(historiaClinica);
    }

    // Actualización completa
    @PutMapping("/{id}")
    public ResponseEntity<HistoriaClinica> actualizarHistoria(
            @PathVariable Long id,
            @RequestBody HistoriaClinica historiaClinica) {

        return historiaClinicaService.actualizarHistoria(id, historiaClinica);
    }

    // Eliminar historia clínica
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> borrarHistoria(@PathVariable Long id) {
        return historiaClinicaService.borrarHistoria(id);
    }

    // Actualización parcial
    @PatchMapping("/{id}")
    public ResponseEntity<HistoriaClinica> actualizacionParcial(
            @PathVariable Long id,
            @RequestBody HistoriaClinica historiaClinica) {

        return historiaClinicaService.actualizacionParcial(id, historiaClinica);
    }
}
package es.pulsoft.spring_hospital.model;

import jakarta.persistence.*;
import java.time.LocalDate;

// Entidad que representa la historia clínica de un paciente
@Entity
@Table(name="historia_clinica")
public class HistoriaClinica {

    // Identificador único de la historia clínica
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // Descripción médica o resumen de la historia clínica del paciente
    private String descripcion;

    // Fecha en la que se registra la historia clínica
    private LocalDate fecha;

    // Relación OneToOne: cada paciente tiene una única historia clínica
    // La clave foránea se almacena en esta tabla (paciente_id)
    @OneToOne
    @JoinColumn(name="paciente_id", unique = true)
    private Paciente paciente;

    // Constructor vacío requerido por JPA
    public HistoriaClinica(){

    }

    // Constructor para crear una historia clínica con datos iniciales
    public HistoriaClinica(String descripcion, LocalDate fecha, Paciente paciente) {
        this.descripcion = descripcion;
        this.fecha = fecha;
        this.paciente = paciente;
    }

    // Obtiene el identificador de la historia clínica
    public Long getId() {
        return id;
    }

    // Obtiene la descripción de la historia clínica
    public String getDescripcion() {
        return descripcion;
    }

    // Establece la descripción de la historia clínica
    public void setDescripcion(String descripcion) {
        this.descripcion = descripcion;
    }

    // Obtiene la fecha de registro de la historia clínica
    public LocalDate getFecha() {
        return fecha;
    }

    // Establece la fecha de la historia clínica
    public void setFecha(LocalDate fecha) {
        this.fecha = fecha;
    }

    // Obtiene el paciente asociado a la historia clínica
    public Paciente getPaciente() {
        return paciente;
    }

    // Asigna un paciente a la historia clínica
    public void setPaciente(Paciente paciente) {
        this.paciente = paciente;
    }
}
package es.pulsoft.spring_hospital.repository;

import es.pulsoft.spring_hospital.model.HistoriaClinica;
import org.springframework.data.jpa.repository.JpaRepository;

import java.time.LocalDate;
import java.util.List;

// Repositorio de acceso a datos para la entidad HistoriaClinica
// Extiende JpaRepository para operaciones CRUD automáticas
public interface HistoriaClinicaRepository extends JpaRepository<HistoriaClinica, Long> {

    // Obtiene historias clínicas dentro de un rango de fechas
    List<HistoriaClinica> findByFechaBetween(LocalDate inicio, LocalDate fin);

    // Busca historias clínicas por fecha exacta
    List<HistoriaClinica> findByFecha(LocalDate inicio);

    // Busca historias clínicas por descripción (búsqueda parcial, ignore case)
    List<HistoriaClinica> findByDescripcionContainingIgnoreCase(String nombre);
}
package es.pulsoft.spring_hospital.service;

import es.pulsoft.spring_hospital.model.HistoriaClinica;
import es.pulsoft.spring_hospital.model.Paciente;
import es.pulsoft.spring_hospital.repository.HistoriaClinicaRepository;
import es.pulsoft.spring_hospital.repository.PacienteRepository;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

import java.time.LocalDate;
import java.util.List;

@Service
public class HistoriaClinicaService {

    private final HistoriaClinicaRepository historiaClinicaRepository;
    private final PacienteRepository pacienteRepository;

    // Inyección de dependencias de repositorios
    public HistoriaClinicaService(HistoriaClinicaRepository historiaClinicaRepository,
                                  PacienteRepository pacienteRepository) {

        this.historiaClinicaRepository = historiaClinicaRepository;
        this.pacienteRepository = pacienteRepository;
    }

    // Filtra historias clínicas por descripción y rango de fechas
    // - Si hay rango de fechas, se prioriza
    // - Si solo hay fecha inicial, filtra por ese día
    // - Si hay descripción, filtra por coincidencia parcial
    // - Si no hay filtros, devuelve todas
    public List<HistoriaClinica> filtrar(String descripcion,
                                         LocalDate inicio,
                                         LocalDate fin) {

        if (inicio != null && fin != null) {
            return historiaClinicaRepository.findByFechaBetween(inicio, fin);
        }

        if (inicio != null) {
            return historiaClinicaRepository.findByFecha(inicio);
        }

        if (descripcion != null) {
            return historiaClinicaRepository.findByDescripcionContainingIgnoreCase(descripcion);
        }

        return historiaClinicaRepository.findAll();
    }

    // Busca una historia clínica por ID
    // Lanza excepción 404 si no existe
    public HistoriaClinica buscarPorId(Long id) {
        return historiaClinicaRepository.findById(id).orElseThrow(() ->
                new ResponseStatusException(HttpStatus.NOT_FOUND,
                        "Historia clinicano encontrada"));
    }

    // Crea una nueva historia clínica con validaciones previas
    public HistoriaClinica crearHistoria(HistoriaClinica historiaClinica) {

        validaciones(historiaClinica);

        return historiaClinicaRepository.save(historiaClinica);
    }

    // Actualiza completamente una historia clínica existente
    public ResponseEntity<HistoriaClinica> actualizarHistoria(Long id,
                                                              HistoriaClinica historiaClinica) {

        HistoriaClinica h = buscarPorId(id);

        validaciones(historiaClinica);

        h.setDescripcion(historiaClinica.getDescripcion());
        h.setFecha(historiaClinica.getFecha());

        Paciente p = pacienteRepository.findById(historiaClinica.getPaciente().getId())
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND,
                        "Paciente no encontrado"));

        h.setPaciente(p);

        return ResponseEntity.ok(historiaClinicaRepository.save(h));
    }

    // Elimina una historia clínica por ID
    public ResponseEntity<Void> borrarHistoria(Long id) {

        HistoriaClinica h = buscarPorId(id);

        historiaClinicaRepository.delete(h);

        return ResponseEntity.noContent().build();
    }

    // Validaciones de negocio para historia clínica
    // - descripción obligatoria
    // - fecha obligatoria
    // - paciente obligatorio
    private void validaciones(HistoriaClinica historiaClinica) {

        if (historiaClinica.getDescripcion() == null ||
                historiaClinica.getDescripcion().trim().isEmpty()) {

            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "La descripcion del historial no puede quedar vacia");
        }

        if (historiaClinica.getFecha() == null) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "La fecha del historial no puede quedar sin asignar");
        }

        if (historiaClinica.getPaciente() == null) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "Una historia tiene que tener una paciente asignado.");
        }
    }

    // Actualización parcial de historia clínica
    // Solo modifica los campos enviados
    public ResponseEntity<HistoriaClinica> actualizacionParcial(Long id,
                                                                HistoriaClinica historiaClinica) {

        HistoriaClinica h = historiaClinicaRepository.findById(id)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND,
                        "Historia no encontrada"));

        if (historiaClinica.getFecha() != null) {
            h.setFecha(historiaClinica.getFecha());
        }

        if (historiaClinica.getDescripcion() != null) {
            h.setDescripcion(historiaClinica.getDescripcion());
        }

        if (historiaClinica.getPaciente() != null) {

            Paciente p = pacienteRepository.findById(historiaClinica.getPaciente().getId())
                    .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND,
                            "Paciente no encontrado"));

            h.setPaciente(historiaClinica.getPaciente());
        }

        return ResponseEntity.ok(historiaClinicaRepository.save(h));
    }
}
4.Medico

4. Medico
Crear un módulo de gestión de médicos.
Cada médico tendrá nombre, especialidad y estará asociado a un departamento.
Además, podrá estar relacionado con múltiples citas de pacientes.
Implementar CRUD completo con Spring Boot.

package es.pulsoft.spring_hospital.controller;

import es.pulsoft.spring_hospital.model.Medico;
import es.pulsoft.spring_hospital.service.MedicoService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/medicos")
public class MedicoController {

    // Servicio de médicos
    private final MedicoService medicoService;

    // Inyección del servicio
    public MedicoController(MedicoService medicoService) {
        this.medicoService = medicoService;
    }

    // Listado de médicos con filtros opcionales
    @GetMapping
    public List<Medico> listarMedicos(
            @RequestParam(required = false) String nombre,
            @RequestParam(required = false) String apellidos,
            @RequestParam(required = false) String especialidad) {

        return medicoService.filtrar(nombre, apellidos, especialidad);
    }

    // Buscar médico por ID
    @GetMapping("/{id}")
    public Medico buscarPorId(@PathVariable Long id) {
        return medicoService.buscarPorId(id);
    }

    // Crear médico
    @PostMapping
    public Medico crearMedico(@RequestBody Medico medico) {
        return medicoService.crearMedico(medico);
    }

    // Actualizar médico completo
    @PutMapping("/{id}")
    public ResponseEntity<Medico> actualizarMedico(
            @PathVariable Long id,
            @RequestBody Medico medico) {

        return medicoService.actualizarMedico(id, medico);
    }

    // Eliminar médico
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> borrarMedico(@PathVariable Long id) {
        return medicoService.borrarMedico(id);
    }

    // Actualización parcial de médico
    @PatchMapping("/{id}")
    public ResponseEntity<Medico> actualizacionParcial(
            @PathVariable Long id,
            @RequestBody Medico medico) {

        return medicoService.actualizacionParcial(id, medico);
    }
}
package es.pulsoft.spring_hospital.model;

import jakarta.persistence.*;
import java.util.List;

// Entidad que representa a un médico dentro del sistema hospitalario
@Entity
@Table(name="medico")
public class Medico {

    // Identificador único del médico
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // Nombre del médico
    private String nombre;

    // Apellidos del médico
    private String apellidos;

    // Especialidad médica (ej: cardiología, pediatría, etc.)
    private String especialidad;

    // Relación ManyToOne: muchos médicos pueden pertenecer a un mismo departamento
    @ManyToOne
    @JoinColumn(name = "departamento_id")
    private Departamento departamento;

    // Relación OneToMany: un médico puede tener muchas citas
    // mappedBy indica que la relación se gestiona desde la entidad Cita
    @OneToMany(mappedBy = "medico")
    private List<Cita> citas;

    // Constructor vacío requerido por JPA
    public Medico(){

    }

    // Constructor para crear un médico con sus datos básicos
    public Medico(String nombre, String apellidos, String especialidad,
                  Departamento departamento, List<Cita> citas) {

        this.nombre = nombre;
        this.apellidos = apellidos;
        this.especialidad = especialidad;
        this.departamento = departamento;
        this.citas = citas;
    }

    // Obtiene el identificador del médico
    public Long getId() {
        return id;
    }

    // Obtiene el nombre del médico
    public String getNombre() {
        return nombre;
    }

    // Establece el nombre del médico
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    // Obtiene los apellidos del médico
    public String getApellidos() {
        return apellidos;
    }

    // Establece los apellidos del médico
    public void setApellidos(String apellidos) {
        this.apellidos = apellidos;
    }

    // Obtiene la especialidad del médico
    public String getEspecialidad() {
        return especialidad;
    }

    // Establece la especialidad del médico
    public void setEspecialidad(String especialidad) {
        this.especialidad = especialidad;
    }

    // Obtiene el departamento del médico
    public Departamento getDepartamento() {
        return departamento;
    }

    // Asigna un departamento al médico
    public void setDepartamento(Departamento departamento) {
        this.departamento = departamento;
    }

    // Obtiene la lista de citas del médico
    public List<Cita> getCitas() {
        return citas;
    }

    // Asigna la lista de citas al médico
    public void setCitas(List<Cita> citas) {
        this.citas = citas;
    }
}
package es.pulsoft.spring_hospital.repository;

import es.pulsoft.spring_hospital.model.Medico;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

// Repositorio de acceso a datos para la entidad Medico
// Extiende JpaRepository para operaciones CRUD automáticas
public interface MedicoRepository extends JpaRepository<Medico, Long> {

    // Filtros combinados (nombre + apellidos + especialidad)
    List<Medico> findByNombreContainingIgnoreCaseAndApellidosContainingIgnoreCaseAndEspecialidadContainingIgnoreCase(
            String nombre, String apellidos, String especialidad);

    // Filtro por nombre + apellidos
    List<Medico> findByNombreContainingIgnoreCaseAndApellidosContainingIgnoreCase(
            String nombre, String apellidos);

    // Filtro por nombre + especialidad
    List<Medico> findByNombreContainingIgnoreCaseAndEspecialidadContainingIgnoreCase(
            String nombre, String especialidad);

    // Filtro por apellidos + especialidad
    List<Medico> findByApellidosContainingIgnoreCaseAndEspecialidadContainingIgnoreCase(
            String apellidos, String especialidad);

    // Filtros individuales
    List<Medico> findByNombreContainingIgnoreCase(String nombre);

    List<Medico> findByApellidosContainingIgnoreCase(String apellidos);

    List<Medico> findByEspecialidadContainingIgnoreCase(String especialidad);
}
package es.pulsoft.spring_hospital.service;

import es.pulsoft.spring_hospital.model.Departamento;
import es.pulsoft.spring_hospital.model.Medico;
import es.pulsoft.spring_hospital.repository.DepartamentoRepository;
import es.pulsoft.spring_hospital.repository.MedicoRepository;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

import java.util.List;

@Service
public class MedicoService {

    private final MedicoRepository medicoRepository;
    private final DepartamentoRepository departamentoRepository;

    // Inyección de dependencias de repositorios
    public MedicoService(MedicoRepository medicoRepository,
                         DepartamentoRepository departamentoRepository) {

        this.medicoRepository = medicoRepository;
        this.departamentoRepository = departamentoRepository;
    }

    // Filtra médicos por nombre, apellidos y especialidad
    // Permite combinaciones múltiples de filtros
    public List<Medico> filtrar(String nombre,
                                String apellidos,
                                String especialidad) {

        if (nombre != null && apellidos != null && especialidad != null) {
            return medicoRepository
                    .findByNombreContainingIgnoreCaseAndApellidosContainingIgnoreCaseAndEspecialidadContainingIgnoreCase(
                            nombre, apellidos, especialidad);
        }

        if (nombre != null && apellidos != null) {
            return medicoRepository
                    .findByNombreContainingIgnoreCaseAndApellidosContainingIgnoreCase(
                            nombre, apellidos);
        }

        if (nombre != null && especialidad != null) {
            return medicoRepository
                    .findByNombreContainingIgnoreCaseAndEspecialidadContainingIgnoreCase(
                            nombre, especialidad);
        }

        if (apellidos != null && especialidad != null) {
            return medicoRepository
                    .findByApellidosContainingIgnoreCaseAndEspecialidadContainingIgnoreCase(
                            apellidos, especialidad);
        }

        if (nombre != null) {
            return medicoRepository.findByNombreContainingIgnoreCase(nombre);
        }

        if (apellidos != null) {
            return medicoRepository.findByApellidosContainingIgnoreCase(apellidos);
        }

        if (especialidad != null) {
            return medicoRepository.findByEspecialidadContainingIgnoreCase(especialidad);
        }

        return medicoRepository.findAll();
    }

    // Busca un médico por su identificador
    // Lanza excepción 404 si no existe
    public Medico buscarPorId(Long id) {
        return medicoRepository.findById(id).orElseThrow(() ->
                new ResponseStatusException(HttpStatus.NOT_FOUND,
                        "Medico no encontrado"));
    }

    // Crea un nuevo médico
    // Valida datos obligatorios y asigna departamento existente
    public Medico crearMedico(Medico medico) {

        validaciones(medico);

        Departamento d = departamentoRepository.findById(medico.getDepartamento().getId())
                .orElseThrow(() ->
                        new ResponseStatusException(HttpStatus.NOT_FOUND,
                                "Departamento no encontrado"));

        medico.setDepartamento(d);

        return medicoRepository.save(medico);
    }

    // Actualiza completamente un médico existente
    public ResponseEntity<Medico> actualizarMedico(Long id, Medico medico) {

        Medico m = buscarPorId(id);

        validaciones(medico);

        m.setNombre(medico.getNombre());
        m.setApellidos(medico.getApellidos());
        m.setEspecialidad(medico.getEspecialidad());

        Departamento d = departamentoRepository.findById(medico.getDepartamento().getId())
                .orElseThrow(() ->
                        new ResponseStatusException(HttpStatus.NOT_FOUND,
                                "Departamento no encontrado"));

        m.setDepartamento(d);

        return ResponseEntity.ok(medicoRepository.save(m));
    }

    // Elimina un médico por su identificador
    public ResponseEntity<Void> borrarMedico(Long id) {

        Medico m = buscarPorId(id);

        medicoRepository.delete(m);

        return ResponseEntity.noContent().build();
    }

    // Validaciones de negocio para médico
    // - Nombre obligatorio
    // - Apellidos obligatorios
    // - Especialidad obligatoria
    // - Departamento obligatorio
    private void validaciones(Medico medico) {

        if (medico.getNombre() == null || medico.getNombre().trim().isEmpty()) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "El nombre de medico no puede quedar sin rellenar");
        }

        if (medico.getApellidos() == null || medico.getApellidos().trim().isEmpty()) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "Los apellidos de medico no puede quedar sin rellenar");
        }

        if (medico.getEspecialidad() == null || medico.getEspecialidad().trim().isEmpty()) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "la especialidad de medico no puede quedar sin rellenar");
        }

        if (medico.getDepartamento() == null ||
                medico.getDepartamento().getId() == null) {

            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "Departamento obligatorio");
        }
    }

    // Actualización parcial de médico
    // Solo modifica los campos enviados en la petición
    public ResponseEntity<Medico> actualizacionParcial(long id, Medico medico) {

        Medico m = medicoRepository.findById(id)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND,
                        "Medico no encontrado"));

        if (medico.getNombre() != null) {
            m.setNombre(medico.getNombre());
        }

        if (medico.getEspecialidad() != null) {
            m.setEspecialidad(medico.getEspecialidad());
        }

        if (medico.getApellidos() != null) {
            m.setApellidos(medico.getApellidos());
        }

        if (medico.getDepartamento() != null) {

            Departamento d = departamentoRepository.findById(medico.getDepartamento().getId())
                    .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND,
                            "Departamento no ecnontrado"));

            m.setDepartamento(d);
        }

        return ResponseEntity.ok(medicoRepository.save(m));
    }
}
5.Paciente

5. Paciente
Desarrollar un sistema de gestión de pacientes.
Cada paciente tendrá datos personales básicos y podrá tener múltiples citas y una historia clínica asociada.
Se deben implementar relaciones JPA y operaciones CRUD completas siguiendo arquitectura en capas.

package es.pulsoft.spring_hospital.controller;

import es.pulsoft.spring_hospital.model.Paciente;
import es.pulsoft.spring_hospital.service.PacienteService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/pacientes")
public class PacienteController {

    // Servicio de pacientes
    private final PacienteService pacienteService;

    // Inyección del servicio
    public PacienteController(PacienteService pacienteService) {
        this.pacienteService = pacienteService;
    }

    // Listado de pacientes con filtros opcionales
    @GetMapping
    public List<Paciente> filtrar(
            @RequestParam(required = false) String nombre,
            @RequestParam(required = false) String apellidos,
            @RequestParam(required = false) String dni,
            @RequestParam(required = false) String telefono) {

        return pacienteService.filtrar(nombre, apellidos, dni, telefono);
    }

    // Buscar paciente por ID
    @GetMapping("/{id}")
    public Paciente buscarPorId(@PathVariable Long id) {
        return pacienteService.buscarPorId(id);
    }

    // Crear paciente
    @PostMapping
    public Paciente crearPaciente(@RequestBody Paciente paciente) {
        return pacienteService.crearPaciente(paciente);
    }

    // Actualizar paciente completo
    @PutMapping("/{id}")
    public ResponseEntity<Paciente> actualizarPaciente(
            @PathVariable Long id,
            @RequestBody Paciente paciente) {

        return pacienteService.actualizarPaciente(id, paciente);
    }

    // Eliminar paciente
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> borrarPaciente(@PathVariable Long id) {
        return pacienteService.borrarPaciente(id);
    }

    // Actualización parcial de paciente
    @PatchMapping("/{id}")
    public ResponseEntity<Paciente> actualizacionParcial(
            @PathVariable Long id,
            @RequestBody Paciente paciente) {

        return pacienteService.actualizacionParcial(id, paciente);
    }
}
package es.pulsoft.spring_hospital.model;

import jakarta.persistence.*;
import java.util.List;

// Entidad que representa a un paciente dentro del sistema hospitalario
@Entity
@Table(name="paciente")
public class Paciente {

    // Identificador único del paciente
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // Nombre del paciente
    private String nombre;

    // Apellidos del paciente
    private String apellidos;

    // DNI del paciente
    private String dni;

    // Número de teléfono del paciente
    private String telefono;

    // Relación OneToMany: un paciente puede tener muchas citas
    @OneToMany(mappedBy = "paciente")
    private List<Cita> citas;

    // Relación OneToOne: cada paciente tiene una única historia clínica
    // mappedBy indica que la relación está gestionada desde HistoriaClinica
    @OneToOne(mappedBy = "paciente")
    private HistoriaClinica historiaClinica;

    // Constructor vacío requerido por JPA
    public Paciente(){

    }

    // Constructor para crear un paciente con sus datos básicos
    public Paciente(String nombre, String apellidos, String dni, String telefono,
                    List<Cita> citas, HistoriaClinica historiaClinica) {

        this.nombre = nombre;
        this.apellidos = apellidos;
        this.dni = dni;
        this.telefono = telefono;
        this.citas = citas;
        this.historiaClinica = historiaClinica;
    }

    // Obtiene el identificador del paciente
    public Long getId() {
        return id;
    }

    // Obtiene el nombre del paciente
    public String getNombre() {
        return nombre;
    }

    // Establece el nombre del paciente
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    // Obtiene los apellidos del paciente
    public String getApellidos() {
        return apellidos;
    }

    // Establece los apellidos del paciente
    public void setApellidos(String apellidos) {
        this.apellidos = apellidos;
    }

    // Obtiene el DNI del paciente
    public String getDni() {
        return dni;
    }

    // Establece el DNI del paciente
    public void setDni(String dni) {
        this.dni = dni;
    }

    // Obtiene el teléfono del paciente
    public String getTelefono() {
        return telefono;
    }

    // Establece el teléfono del paciente
    public void setTelefono(String telefono) {
        this.telefono = telefono;
    }

    // Obtiene la lista de citas del paciente
    public List<Cita> getCitas() {
        return citas;
    }

    // Asigna la lista de citas al paciente
    public void setCitas(List<Cita> citas) {
        this.citas = citas;
    }

    // Obtiene la historia clínica del paciente
    public HistoriaClinica getHistoriaClinica() {
        return historiaClinica;
    }

    // Asigna la historia clínica al paciente
    public void setHistoriaClinica(HistoriaClinica historiaClinica) {
        this.historiaClinica = historiaClinica;
    }
}
package es.pulsoft.spring_hospital.repository;

import es.pulsoft.spring_hospital.model.Paciente;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

// Repositorio de acceso a datos para la entidad Paciente
// Extiende JpaRepository para operaciones CRUD automáticas
public interface PacienteRepository extends JpaRepository<Paciente, Long> {

    // Busca pacientes por nombre (búsqueda parcial, ignore case)
    List<Paciente> findByNombreContainingIgnoreCase(String nombre);

    // Busca pacientes por apellidos (búsqueda parcial, ignore case)
    List<Paciente> findByApellidosContainingIgnoreCase(String apellidos);

    // Busca pacientes por DNI (búsqueda parcial, ignore case)
    List<Paciente> findByDniContainingIgnoreCase(String dni);

    // Busca pacientes por teléfono (búsqueda parcial, ignore case)
    List<Paciente> findByTelefonoContainingIgnoreCase(String telefono);
}
package es.pulsoft.spring_hospital.service;

import es.pulsoft.spring_hospital.model.HistoriaClinica;
import es.pulsoft.spring_hospital.model.Paciente;
import es.pulsoft.spring_hospital.repository.HistoriaClinicaRepository;
import es.pulsoft.spring_hospital.repository.PacienteRepository;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

import java.util.List;

@Service
public class PacienteService {

    private final PacienteRepository pacienteRepository;
    private final HistoriaClinicaRepository historiaClinicaRepository;

    // Inyección de dependencias de repositorios
    public PacienteService(PacienteRepository pacienteRepository,
                           HistoriaClinicaRepository historiaClinicaRepository) {

        this.pacienteRepository = pacienteRepository;
        this.historiaClinicaRepository = historiaClinicaRepository;
    }

    // Filtra pacientes por nombre, apellidos, DNI o teléfono
    // Aplica filtros individuales según los parámetros recibidos
    public List<Paciente> filtrar(String nombre,
                                  String apellidos,
                                  String dni,
                                  String telefono) {

        if (nombre != null && !nombre.isBlank()) {
            return pacienteRepository.findByNombreContainingIgnoreCase(nombre);
        }

        if (apellidos != null && !apellidos.isBlank()) {
            return pacienteRepository.findByApellidosContainingIgnoreCase(apellidos);
        }

        if (dni != null && !dni.isBlank()) {
            return pacienteRepository.findByDniContainingIgnoreCase(dni);
        }

        if (telefono != null && !telefono.isBlank()) {
            return pacienteRepository.findByTelefonoContainingIgnoreCase(telefono);
        }

        return pacienteRepository.findAll();
    }

    // Busca un paciente por su identificador
    // Lanza excepción 404 si no existe
    public Paciente buscarPorId(Long id) {
        return pacienteRepository.findById(id).orElseThrow(() ->
                new ResponseStatusException(HttpStatus.NOT_FOUND,
                        "Paciente no ecnontrado"));
    }

    // Crea un nuevo paciente aplicando validaciones de negocio
    public Paciente crearPaciente(Paciente paciente) {

        validaciones(paciente);

        return pacienteRepository.save(paciente);
    }

    // Actualiza completamente un paciente existente
    public ResponseEntity<Paciente> actualizarPaciente(Long id, Paciente paciente) {

        Paciente p = buscarPorId(id);

        validaciones(paciente);

        p.setNombre(paciente.getNombre());
        p.setApellidos(paciente.getApellidos());
        p.setDni(paciente.getDni());
        p.setTelefono(paciente.getTelefono());

        return ResponseEntity.ok(pacienteRepository.save(p));
    }

    // Elimina un paciente por su identificador
    public ResponseEntity<Void> borrarPaciente(Long id) {

        Paciente p = buscarPorId(id);

        pacienteRepository.delete(p);

        return ResponseEntity.noContent().build();
    }

    // Validaciones de negocio para paciente
    // Todos los campos básicos son obligatorios
    private void validaciones(Paciente paciente) {

        if (paciente.getNombre() == null || paciente.getNombre().trim().isEmpty()) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "El nombre del paciente no puede quedar sin cubrir");
        }

        if (paciente.getApellidos() == null || paciente.getApellidos().trim().isEmpty()) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "Los apellidos del paciente no puede quedar sin cubrir");
        }

        if (paciente.getDni() == null || paciente.getDni().trim().isEmpty()) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "El DNI del paciente no puede quedar sin cubrir");
        }

        if (paciente.getTelefono() == null || paciente.getTelefono().trim().isEmpty()) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "El telefono del paciente no puede quedar sin cubrir");
        }
    }

    // Actualización parcial de paciente
    // Solo modifica los campos enviados en la petición
    public ResponseEntity<Paciente> actualizacionParcial(Long id, Paciente paciente) {

        Paciente p = pacienteRepository.findById(id)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND,
                        "Paciente no encontrado"));

        if (paciente.getNombre() != null) {
            p.setNombre(paciente.getNombre());
        }

        if (paciente.getApellidos() != null) {
            p.setApellidos(paciente.getApellidos());
        }

        if (paciente.getDni() != null) {
            p.setDni(paciente.getDni());
        }

        if (paciente.getTelefono() != null) {
            p.setTelefono(paciente.getTelefono());
        }

        if (paciente.getHistoriaClinica() != null) {

            HistoriaClinica h = historiaClinicaRepository.findById(
                    paciente.getHistoriaClinica().getId()
            ).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND,
                    "Historia clinica no encontrada"));

            p.setHistoriaClinica(paciente.getHistoriaClinica());
        }

        return ResponseEntity.ok(pacienteRepository.save(p));
    }
}