!> 吸着(insulator)モデルのメインループを実行し、電荷堆積と統計更新を行うモジュール。
module bem_simulator
!$ use omp_lib
  use, intrinsic :: iso_fortran_env, only: output_unit
  use bem_kinds, only: dp, i32, i64
  use bem_types, only: sim_stats, mesh_type, particles_soa, hit_info, injection_state, sim_config
  use bem_app_config, only: app_config, init_particle_batch_from_config
  use bem_field_solver, only: field_solver_type
  use bem_pusher, only: boris_push
  use bem_collision, only: find_first_hit
  use bem_boundary, only: apply_box_boundary
  use bem_mpi, only: mpi_context, mpi_is_root, mpi_allreduce_sum_real_dp_array, mpi_allreduce_sum_i32_array
  implicit none
  private

  public :: run_absorption_insulator

  interface
    !> 粒子をバッチ処理し、衝突時は要素へ電荷堆積、非衝突時は脱出として統計を更新する。
    module subroutine run_absorption_insulator( &
      mesh, app, stats, history_unit, history_stride, initial_stats, inject_state, mpi, mesh_potential_v, &
      potential_history_unit &
      )
      type(mesh_type), intent(inout) :: mesh
      type(app_config), intent(in) :: app
      type(sim_stats), intent(out) :: stats
      integer, intent(in), optional :: history_unit
      integer(i32), intent(in), optional :: history_stride
      type(sim_stats), intent(in), optional :: initial_stats
      type(injection_state), intent(inout), optional :: inject_state
      type(mpi_context), intent(in), optional :: mpi
      real(dp), allocatable, intent(out), optional :: mesh_potential_v(:)
      integer, intent(in), optional :: potential_history_unit
    end subroutine run_absorption_insulator

    !> 1バッチ分の粒子群と作業配列を初期化する。
    module subroutine prepare_batch_state( &
      mesh, app, stats, local_batch_idx, batch_idx, dq_thread, pcls_batch, escaped_boundary_flag, absorbed_flag, &
      photo_emission_dq, mpi, inject_state &
      )
      type(mesh_type), intent(in) :: mesh
      type(app_config), intent(in) :: app
      type(sim_stats), intent(in) :: stats
      integer(i32), intent(in) :: local_batch_idx
      integer(i32), intent(out) :: batch_idx
      real(dp), intent(inout) :: dq_thread(:, :)
      type(particles_soa), intent(out) :: pcls_batch
      logical, allocatable, intent(inout) :: escaped_boundary_flag(:)
      logical, allocatable, intent(inout) :: absorbed_flag(:)
      real(dp), intent(out) :: photo_emission_dq(:)
      type(mpi_context), intent(in) :: mpi
      type(injection_state), intent(inout), optional :: inject_state
    end subroutine prepare_batch_state

    !> 1バッチぶんの粒子を前進させ、スレッド別に堆積電荷を集計する。
    module subroutine process_particle_batch( &
      mesh, app, field_solver, pcls_batch, dq_thread, escaped_boundary_flag, absorbed_flag, bfield &
      )
      type(mesh_type), intent(in) :: mesh
      type(app_config), intent(in) :: app
      type(field_solver_type), intent(inout) :: field_solver
      type(particles_soa), intent(inout) :: pcls_batch
      real(dp), intent(inout) :: dq_thread(:, :)
      logical, intent(inout) :: escaped_boundary_flag(:)
      logical, intent(inout) :: absorbed_flag(:)
      real(dp), intent(in) :: bfield(3)
    end subroutine process_particle_batch

    !> スレッド別に集計した電荷差分をメッシュへ反映し、相対変化量を返す。
    module subroutine commit_batch_charge(mesh, q_floor, dq_thread, photo_emission_dq, dq, rel, mpi)
      type(mesh_type), intent(inout) :: mesh
      real(dp), intent(in) :: q_floor
      real(dp), intent(in) :: dq_thread(:, :)
      real(dp), intent(in) :: photo_emission_dq(:)
      real(dp), intent(out) :: dq(:)
      real(dp), intent(out) :: rel
      type(mpi_context), intent(in) :: mpi
    end subroutine commit_batch_charge

    !> 今バッチの粒子処理結果を局所集計する。
    module subroutine count_batch_outcomes(pcls_batch, escaped_boundary_flag, absorbed_flag, batch_counts)
      type(particles_soa), intent(in) :: pcls_batch
      logical, intent(in) :: escaped_boundary_flag(:)
      logical, intent(in) :: absorbed_flag(:)
      integer(i32), intent(out) :: batch_counts(5)
    end subroutine count_batch_outcomes

    !> バッチ完了後の統計値を更新する。
    module subroutine accumulate_batch_stats(stats, batch_counts, rel)
      type(sim_stats), intent(inout) :: stats
      integer(i32), intent(in) :: batch_counts(5)
      real(dp), intent(in) :: rel
    end subroutine accumulate_batch_stats

    !> ルートランクでバッチ完了時の進捗と相対変化量を標準出力へ表示する。
    module subroutine print_batch_progress(batch_idx, final_batch_idx, rel_change)
      integer(i32), intent(in) :: batch_idx
      integer(i32), intent(in) :: final_batch_idx
      real(dp), intent(in) :: rel_change
    end subroutine print_batch_progress

    !> 履歴出力が有効で、指定ストライドを満たす場合のみ電荷履歴を書き出す。
    module subroutine maybe_write_history_snapshot(history_enabled, hist_unit, hist_stride, stats, rel, q_elem)
      logical, intent(in) :: history_enabled
      integer, intent(in) :: hist_unit
      integer(i32), intent(in) :: hist_stride
      type(sim_stats), intent(in) :: stats
      real(dp), intent(in) :: rel
      real(dp), intent(in) :: q_elem(:)
    end subroutine maybe_write_history_snapshot

    !> 現時点の要素電荷を CSV 行群として書き出す。
    module subroutine write_history_snapshot(unit_id, batch_idx, processed_particles, rel_change, q_elem)
      integer, intent(in) :: unit_id
      integer(i32), intent(in) :: batch_idx
      integer(i64), intent(in) :: processed_particles
      real(dp), intent(in) :: rel_change
      real(dp), intent(in) :: q_elem(:)
    end subroutine write_history_snapshot

    !> 電位履歴出力条件を満たすバッチだけ電位スナップショットを書き出す。
    module subroutine maybe_write_potential_history_snapshot( &
      potential_history_enabled, pot_hist_unit, hist_stride, stats, &
      field_solver, mesh, sim, potential_buf &
      )
      logical, intent(in) :: potential_history_enabled
      integer, intent(in) :: pot_hist_unit
      integer(i32), intent(in) :: hist_stride
      type(sim_stats), intent(in) :: stats
      type(field_solver_type), intent(inout) :: field_solver
      type(mesh_type), intent(inout) :: mesh
      type(sim_config), intent(in) :: sim
      real(dp), intent(inout) :: potential_buf(:)
    end subroutine maybe_write_potential_history_snapshot

    !> 全要素電位を電位履歴CSV形式で1バッチ分書き出す。
    module subroutine write_potential_history_snapshot(unit_id, batch_idx, potential_v)
      integer, intent(in) :: unit_id
      integer(i32), intent(in) :: batch_idx
      real(dp), intent(in) :: potential_v(:)
    end subroutine write_potential_history_snapshot

  end interface

end module bem_simulator
