!> Public radiation data contract.
!!
!! Radiation physics kernels should consume only these types plus the static mesh.
!! MPI gather/reduction, flow ownership, restart, and energy coupling remain in
!! the radiation driver.  Model developers implement files under
!! `src/radiation/models/` and should not need MPI calls.
module mod_radiation_types
   use mod_precision, only : rk, zero, name_len, path_len
   implicit none

   private
   public :: radiation_context_t, radiation_state_t, radiation_source_t
   public :: allocate_radiation_state, free_radiation_state
   public :: allocate_radiation_source, free_radiation_source

   type :: radiation_context_t
      logical :: enabled = .false.
      character(len=name_len) :: model = 'none'
      integer :: rad_rank = -1
      integer :: rad_size = 0
      integer :: n_wavenumbers = 0
      integer :: wn_first = 0
      integer :: wn_last = -1
      integer :: nlocal_wavenumbers = 0
      integer :: ncells = 0
      integer :: nfaces = 0
      integer :: n_species = 0
      character(len=name_len), allocatable :: species_name(:)
      integer, allocatable :: species_index(:)
      integer :: n_scalars = 0
      character(len=name_len), allocatable :: scalar_name(:)
      character(len=name_len) :: pressure_source = 'background'
      logical :: mesh_cached = .false.
      logical :: debug = .false.
      logical :: write_diagnostics = .true.
      logical :: setup_written = .false.
      logical :: diagnostics_initialized = .false.
      character(len=path_len) :: setup_file = ''
      character(len=path_len) :: diagnostics_file = ''
   end type radiation_context_t

   type :: radiation_state_t
      integer :: step = 0
      real(rk) :: time = zero
      real(rk) :: dt = zero
      integer :: ncells = 0
      integer :: n_species = 0
      integer :: n_scalars = 0
      real(rk), allocatable :: temperature(:)
      real(rk), allocatable :: pressure(:)
      real(rk), allocatable :: Y(:,:)       ! selected radiation species x ncells
      real(rk), allocatable :: scalars(:,:) ! reserved selected scalar arrays x ncells
      integer, allocatable :: phase(:)      ! reserved optional integer phase per cell
   end type radiation_state_t

   type :: radiation_source_t
      real(rk), allocatable :: qrad(:) ! [W/m^3], positive adds energy to gas
   end type radiation_source_t

contains

   subroutine allocate_radiation_state(state, ncells, n_species, n_scalars)
      type(radiation_state_t), intent(inout) :: state
      integer, intent(in) :: ncells, n_species, n_scalars
      call free_radiation_state(state)
      state%ncells = ncells
      state%n_species = max(0, n_species)
      state%n_scalars = max(0, n_scalars)
      allocate(state%temperature(ncells), state%pressure(ncells))
      state%temperature = zero
      state%pressure = zero
      if (state%n_species > 0) then
         allocate(state%Y(state%n_species, ncells))
         state%Y = zero
      end if
      if (state%n_scalars > 0) then
         allocate(state%scalars(state%n_scalars, ncells))
         state%scalars = zero
      end if
   end subroutine allocate_radiation_state

   subroutine free_radiation_state(state)
      type(radiation_state_t), intent(inout) :: state
      if (allocated(state%temperature)) deallocate(state%temperature)
      if (allocated(state%pressure)) deallocate(state%pressure)
      if (allocated(state%Y)) deallocate(state%Y)
      if (allocated(state%scalars)) deallocate(state%scalars)
      if (allocated(state%phase)) deallocate(state%phase)
      state%step = 0
      state%time = zero
      state%dt = zero
      state%ncells = 0
      state%n_species = 0
      state%n_scalars = 0
   end subroutine free_radiation_state

   subroutine allocate_radiation_source(source, ncells)
      type(radiation_source_t), intent(inout) :: source
      integer, intent(in) :: ncells
      call free_radiation_source(source)
      allocate(source%qrad(ncells))
      source%qrad = zero
   end subroutine allocate_radiation_source

   subroutine free_radiation_source(source)
      type(radiation_source_t), intent(inout) :: source
      if (allocated(source%qrad)) deallocate(source%qrad)
   end subroutine free_radiation_source

end module mod_radiation_types
