!> MPI infrastructure for the radiation solver.
!!
!! This module manages the parallel execution of the radiation transport 
!! solver. Unlike the flow solver which uses a replicated mesh, the 
!! radiation solver can be configured with its own communicator and 
!! task decomposition logic (e.g., distributing rays or discrete ordinates).
module mod_mpi_radiation
   use mpi_f08
   use mod_precision, only : fatal_error
   implicit none

   private

   public :: radiation_mpi_t
   public :: radiation_mpi_initialize, radiation_mpi_finalize
   public :: radiation_task_bounds, radiation_configure_spectral

   !> MPI context for radiation operations.
   type :: radiation_mpi_t
      type(MPI_Comm) :: comm = MPI_COMM_NULL !< MPI Communicator.
      integer :: rank = -1                   !< Local rank ID.
      integer :: nprocs = 0                  !< Total number of radiation processors.
      integer :: first_task = 0              !< First task index owned by this rank.
      integer :: last_task = -1              !< Last task index owned by this rank.
      integer :: nlocal_tasks = 0            !< Total number of tasks owned locally.
      integer :: first_wavenumber = 0        !< Alias for first spectral/wavenumber index owned by this radiation rank.
      integer :: last_wavenumber = -1        !< Alias for last spectral/wavenumber index owned by this radiation rank.
      integer :: nlocal_wavenumbers = 0      !< Number of spectral/wavenumber tasks owned locally.
   end type radiation_mpi_t

contains

   !> Initializes the radiation MPI context by duplicating a parent communicator.
   !!
   !! @param rad The radiation context to initialize.
   !! @param comm_parent The parent communicator (usually MPI_COMM_WORLD).
   !! @param n_tasks Optional total number of tasks to decompose immediately.
   subroutine radiation_mpi_initialize(rad, comm_parent, n_tasks)
      type(radiation_mpi_t), intent(inout) :: rad
      type(MPI_Comm), intent(in) :: comm_parent
      integer, intent(in), optional :: n_tasks

      integer :: ierr

      call radiation_mpi_finalize(rad)

      call MPI_Comm_dup(comm_parent, rad%comm, ierr)
      call check_mpi(ierr, 'MPI_Comm_dup radiation')

      call MPI_Comm_rank(rad%comm, rad%rank, ierr)
      call check_mpi(ierr, 'MPI_Comm_rank radiation')

      call MPI_Comm_size(rad%comm, rad%nprocs, ierr)
      call check_mpi(ierr, 'MPI_Comm_size radiation')

      if (present(n_tasks)) then
         call radiation_task_bounds(rad, n_tasks)
      end if
   end subroutine radiation_mpi_initialize


   !> Releases radiation MPI resources.
   subroutine radiation_mpi_finalize(rad)
      type(radiation_mpi_t), intent(inout) :: rad

      integer :: ierr

      if (rad%comm /= MPI_COMM_NULL) then
         call MPI_Comm_free(rad%comm, ierr)
         call check_mpi(ierr, 'MPI_Comm_free radiation')
      end if

      rad%comm = MPI_COMM_NULL
      rad%rank = -1
      rad%nprocs = 0
      rad%first_task = 0
      rad%last_task = -1
      rad%nlocal_tasks = 0
      rad%first_wavenumber = 0
      rad%last_wavenumber = -1
      rad%nlocal_wavenumbers = 0
   end subroutine radiation_mpi_finalize


   !> Performs contiguous task decomposition for the radiation solver.
   !!
   !! @param rad The radiation context to update.
   !! @param n_tasks Total number of discrete tasks (e.g., rays).
   subroutine radiation_task_bounds(rad, n_tasks)
      type(radiation_mpi_t), intent(inout) :: rad
      integer, intent(in) :: n_tasks

      integer :: base, rem

      if (n_tasks < 0) call fatal_error('mpi_radiation', 'n_tasks cannot be negative')
      if (rad%nprocs <= 0) call fatal_error('mpi_radiation', 'radiation communicator is not initialized')

      base = n_tasks / rad%nprocs
      rem = mod(n_tasks, rad%nprocs)

      if (rad%rank < rem) then
         rad%nlocal_tasks = base + 1
         rad%first_task = rad%rank * (base + 1) + 1
      else
         rad%nlocal_tasks = base
         rad%first_task = rem * (base + 1) + (rad%rank - rem) * base + 1
      end if
      rad%last_task = rad%first_task + rad%nlocal_tasks - 1
      rad%first_wavenumber = rad%first_task
      rad%last_wavenumber = rad%last_task
      rad%nlocal_wavenumbers = rad%nlocal_tasks
   end subroutine radiation_task_bounds


   !> Configure spectral radiation decomposition.
   !!
   !! This is intentionally a thin alias over radiation_task_bounds: flow MPI
   !! remains spatial, while radiation MPI owns contiguous spectral/wavenumber
   !! tasks.  Radiation kernels are expected to loop over their owned
   !! wavenumbers and the full replicated mesh.
   subroutine radiation_configure_spectral(rad, n_wavenumbers)
      type(radiation_mpi_t), intent(inout) :: rad
      integer, intent(in) :: n_wavenumbers

      call radiation_task_bounds(rad, n_wavenumbers)
   end subroutine radiation_configure_spectral


   !> Internal helper for MPI error checking.
   subroutine check_mpi(ierr, where)
      integer, intent(in) :: ierr
      character(len=*), intent(in) :: where

      if (ierr /= MPI_SUCCESS) call fatal_error('mpi_radiation', trim(where)//' failed')
   end subroutine check_mpi

end module mod_mpi_radiation


