module testplanetunits
  use testHelper
  use voltapp
  use gamapp
  use chmpunits
  use planethelper
  use uservoltic
  use xml_input
  use ioH5
  use kdefs
  use msphutils, only : RadIonosphere

  implicit none

contains

  @before
  subroutine firstSerial()
  end subroutine firstSerial

  @after
  subroutine lastSerial()
  end subroutine lastSerial

  subroutine checkVoltron(vApp, rp_m, ri_m, grav, magMom, psiCorot, doGrav)
    type(voltApp_T), intent(in) :: vApp
    real(rp), intent(in) :: rp_m, ri_m, grav, magMom, psiCorot
    logical, intent(in) :: doGrav

    associate(pName => vApp%planet%name)
    @assertLessThanOrEqual(abs(vApp%planet%rp_m - rp_m)        , 1._rp, "Voltron didn't properly set "//trim(pName)//"'s surface radius")
    @assertLessThanOrEqual(abs(vApp%planet%ri_m  - ri_m)       , 1._rp, "Voltron didn't properly set "//trim(pName)//"'s ionosphere radius")
    @assertLessThanOrEqual(abs(vApp%planet%grav - grav)        , 1E-3_rp, "Voltron didn't properly set "//trim(pName)//"'s gravity")
    @assertLessThanOrEqual(abs(vApp%planet%magMoment - magMom) , 1E-3_rp, "Voltron didn't properly set "//trim(pName)//"'s dipole moment")
    @assertLessThanOrEqual(abs(vApp%planet%psiCorot - psiCorot), 1E-3_rp, "Voltron didn't properly set "//trim(pName)//"'s' corotation potential")
    @assertTrue(vApp%planet%doGrav .eq. doGrav, "Voltron didn't properly enable doGrav for "//trim(pName))
    end associate
  end subroutine checkVoltron

  subroutine checkGamera(vApp, gApp)
    type(voltApp_T), intent(in) :: vApp
    class(gamApp_T), intent(in) :: gApp
    
    ! Gam units
    real(rp) :: gv0, gT0, gB0, gP0, M0, GM0_t

    call getGamPlanetNorms(vApp%planet, gv0=gv0, gT0=gT0, gB0=gB0, gP0=gP0, M0=M0, GM0=GM0_t)
    associate(pName => vApp%planet%name)
    @assertLessThanOrEqual(abs(gApp%Model%Units%gT0 - gT0), 1E-8_rp, "Gamera didn't get same Time scale as test for "//trim(pName))
    @assertLessThanOrEqual(abs(gApp%Model%Units%gB0 - gB0), 1E-8_rp, "Gamera didn't get same Mag scale as test for "//trim(pName))
    @assertLessThanOrEqual(abs(gApp%Model%Units%gP0 - gP0), 1E-8_rp, "Gamera didn't get same Pressure scale as test for "//trim(pName))
    @assertLessThanOrEqual(abs(gApp%Model%MagM0 - M0)     , 1E-8_rp, "Gamera didn't get same Dipole as test for "//trim(pName))
    @assertLessThanOrEqual(abs(RadIonosphere() - vApp%planet%ri_m/vApp%planet%rp_m), 1E-8_rp, "Gamera didn't get same ionosphere radius as Voltron for "//trim(pName))
    end associate
  end subroutine checkGamera

  !subroutine checkRCM(vApp)
  !  type(voltApp_T), intent(in) :: vApp
  !  associate(pName => vApp%planet%name)
  !  select type(rcmApp=>vApp%imagApp)
  !      type is (rcmIMAG_T)
  !          @assertLessThanOrEqual(abs(rcmApp%rcmCpl%planet_radius - vApp%planet%rp_m), 1E-8_rp, "RCM Planet Radius differs from voltron for "//trim(pName))
  !          @assertLessThanOrEqual(abs(rcmApp%rcmCpl%iono_radius - vApp%planet%ri_m), 1E-8_rp, "RCM Planet Radius differs from voltron for "//trim(pName))
  !          ! TODO: ways to check planetM0g and RIonRCM where/when its actually used
  !  end select
  !  end associate
  !end subroutine checkRCM

  subroutine checkChimp(vApp)
    type(voltApp_T), intent(in) :: vApp
    real(rp) :: ebScl !CGS->Code EB units

    real(rp) :: gv0, gB0, gP0

    call getGamPlanetNorms(vApp%planet, gv0=gv0, gB0=gB0, gP0=gP0)

    ebScl = (qe_cgs*vApp%planet%rp_m*1.e2/Me_cgs)/(vc_cgs**2.0)
    associate(pName => vApp%planet%name)
    !These checks should cover every variable CHIMP gets from planethelper in Voltron mode
    @assertLessThanOrEqual(abs(L0 - vApp%planet%rp_m*1.e2), 1E-4_rp, "CHIMP length scale differs from voltron for "//trim(pName))
    @assertLessThanOrEqual(abs(M0g - vApp%planet%magMoment), 1E-8_rp, "CHIMP mag moment differs from voltron for "//trim(pName))
    @assertLessThanOrEqual(abs(in2cms - 100*gv0), 1E-8_rp, "CHIMP in2cms calc. differs from calc. via voltron for "//trim(pName))
    @assertLessThanOrEqual(abs(in2G - gB0/G2nT), 1E-8_rp, "CHIMP in2G calc. differs from calc. via voltron for "//trim(pName))
    @assertLessThanOrEqual(abs(inPscl - gP0), 1E-8_rp, "CHIMP in2Pscl calc. differs from calc. via voltron for "//trim(pName))
    
    end associate
  end subroutine checkChimp

  @test
  subroutine testEarth()
    type(voltApp_T) :: vApp
    character(len=strLen) :: xmlName = 'cmriD_Earth.xml'

    vApp%vOptions%gamUserInitFunc => initUser
    call initVoltron(vApp, xmlName)

    ! Run tests
    call checkVoltron(vApp, REarth, RionE*1E6_rp, 9.807_rp, EarthM0g, EarthPsi0, .true.)
    call checkGamera(vApp, vApp%gApp)
    !call checkRCM(vApp)
    !Does REMIX need to be checked? Only relies on msphutil's RadIonosphere() (2021/10/12)
    call checkChimp(vApp)

  end subroutine testEarth

  @test
  subroutine testJupiter()
    type(voltApp_T) :: vApp
    character(len=strLen) :: xmlName = 'cmriD_Jupiter.xml'
    real(rp) :: jupCorot

    jupCorot = -2.5*1702.9*92.0
    vApp%vOptions%gamUserInitFunc => initUser
    call initVoltron(vApp, xmlName)

    ! Run tests
    call checkVoltron(vApp, RJupiterXE*REarth, 1.01*RJupiterXE*REarth, 24.79_rp, JupiterM0g, jupCorot, .true.)
    call checkGamera(vApp, vApp%gApp)
    !call checkRCM(vApp)
    !Does REMIX need to be checked? Only relies on msphutil's RadIonosphere() (2021/10/12)
    call checkChimp(vApp)

  end subroutine testJupiter

  @test
  subroutine testNewPlanet() ! Arbitrary, not real planet
    type(voltApp_T) :: vApp
    character(len=strLen) :: xmlName = 'cmriD_NewPlanet.xml'
    type(XML_Input_T) :: inpXML
    real(rp) :: corotXML

    vApp%vOptions%gamUserInitFunc => initUser
    call initVoltron(vApp, xmlName)

    ! For this test, we should get corot potential right from xml cause we don't have a real pre-set value for a fake planet.
    ! This does check if Voltron and Gamera are getting the right potential from xml
    ! Currently, we know RCM does not, and that kai2geo doesn't need to cause its only for Earth
    !  so, RCM and kai2geo should only be used for Earth Earth
    inpXML = New_XML_Input(trim(xmlName),"Kaiju/GAMERA",.true.)
    call inpXML%Set_Val(corotXML , "prob/Psi0", EarthM0g)

    ! Run tests
    call checkVoltron(vApp, 1.3*REarth, 1.01*1.3*REarth, 12.0_rp, 0.3*EarthM0g, corotXML, .true.)
    call checkGamera(vApp, vApp%gApp)
    !call checkRCM(vApp)
    !Does REMIX need to be checked? Only relies on msphutil's RadIonosphere() (2021/10/12)
    call checkChimp(vApp)

  end subroutine testNewPlanet

end module testplanetunits
