!> Species-name registry helpers shared by chemistry, boundaries, radiation, and diagnostics.
!!
!! The solver may use a Cantera-discovered species ordering internally. User
!! inputs and radiation model selections should therefore be resolved by name,
!! not by hard-coded numeric indices. This small module keeps that name lookup
!! behavior consistent across subsystems.
module mod_species_registry
   use mod_precision, only : name_len, lowercase, fatal_error
   implicit none

   private

   public :: species_registry_t
   public :: species_index_of, species_require_index
   public :: species_names_match

   !> Object-oriented species registry container for cleaner access.
   type :: species_registry_t
      integer :: nspecies = 0                            !< Number of registered species.
      character(len=name_len), allocatable :: name(:)    !< Array of registered species names.
   contains
      procedure :: index_of => registry_index_of
      procedure :: require_index => registry_require_index
   end type species_registry_t

contains

   !> Returns true if two species names are identical (case-insensitive, whitespace-trimmed).
   !!
   !! @param a First name.
   !! @param b Second name.
   logical function species_names_match(a, b)
      character(len=*), intent(in) :: a !< First name string to compare.
      character(len=*), intent(in) :: b !< Second name string to compare.
      species_names_match = trim(lowercase(adjustl(a))) == trim(lowercase(adjustl(b)))
   end function species_names_match

   !> Searches the name array for a target name and returns its 1-based index, or 0 if not found.
   !!
   !! @param names Array of registered names.
   !! @param nspecies Size of the names array to search.
   !! @param target The target name to search for.
   integer function species_index_of(names, nspecies, target) result(idx)
      character(len=*), intent(in) :: names(:) !< Array of species names.
      integer, intent(in) :: nspecies          !< Number of species to search.
      character(len=*), intent(in) :: target   !< Target name to look up.
      integer :: k                             !< Loop counter.

      idx = 0
      if (nspecies <= 0 .or. len_trim(target) == 0) return
      do k = 1, min(nspecies, size(names))
         if (species_names_match(names(k), target)) then
            idx = k
            return
         end if
      end do
   end function species_index_of

   !> Searches for a target name and returns its index, or halts simulation with a fatal error if not found.
   !!
   !! @param names Array of registered names.
   !! @param nspecies Size of the names array.
   !! @param target The target name to require.
   !! @param owner The calling subsystem module name for traceback.
   integer function species_require_index(names, nspecies, target, owner) result(idx)
      character(len=*), intent(in) :: names(:) !< Array of species names.
      integer, intent(in) :: nspecies          !< Number of species.
      character(len=*), intent(in) :: target   !< Target name to search.
      character(len=*), intent(in) :: owner    !< Subsystem name for error traceback.

      idx = species_index_of(names, nspecies, target)
      if (idx <= 0) then
         call fatal_error(trim(owner), 'unknown species name "'//trim(target)//'"')
      end if
   end function species_require_index

   !> Bound procedure to find the index of a species from the registry instance.
   !!
   !! @param this The species registry instance.
   !! @param target The target species name to lookup.
   integer function registry_index_of(this, target) result(idx)
      class(species_registry_t), intent(in) :: this !< Registry object context.
      character(len=*), intent(in) :: target        !< Target species name.
      if (.not. allocated(this%name)) then
         idx = 0
      else
         idx = species_index_of(this%name, this%nspecies, target)
      end if
   end function registry_index_of

   !> Bound procedure to find the index of a species, raising a fatal error if it is missing.
   !!
   !! @param this The species registry instance.
   !! @param target The target species name to require.
   !! @param owner The calling subsystem module name.
   integer function registry_require_index(this, target, owner) result(idx)
      class(species_registry_t), intent(in) :: this !< Registry object context.
      character(len=*), intent(in) :: target        !< Target species name.
      character(len=*), intent(in) :: owner         !< Subsystem name for traceback.
      if (.not. allocated(this%name)) then
         call fatal_error(trim(owner), 'species registry is not initialized')
      end if
      idx = species_require_index(this%name, this%nspecies, target, owner)
   end function registry_require_index

end module mod_species_registry
