/*
 * RiskScape™ Copyright New Zealand Institute for Earth Science Limited
 * (Earth Sciences New Zealand) is distributed for research purposes only
 * under the terms of AGPLv3.
 *
 * RiskScape™ Copyright 2026 New Zealand Institute for Earth Science
 * Limited (Earth Sciences New Zealand). All rights reserved. Source code
 * available under the AGPLv3.
 * 
 * This program is free software: you can redistribute it and/or modify it under
 *  the terms of the GNU Affero General Public License as published by the Free
 *  Software Foundation, either version 3 of the License, or (at your option) any
 *  later version.
 * 
 * This program is distributed for RESEARCH PURPOSES ONLY, in the hope that it will
 * be useful for research and education initiatives.
 * 
 * If you are not a researcher, or you are a researcher who wishes to use this
 * program on terms other than AGPLv3 (including those who wish to restrict the
 * distribution of any source code created using this program), please contact:
 * https://riskscape.org.nz
 * 
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Affero General Public License for more details.  You should have received a copy
 * of the GNU Affero General Public License along with this program.  If not, see
 * <http://www.gnu.org/licenses/>.
 * 
 * By way of summary only, under the AGPLv3:
 *     • Permissions of this strongest copyleft license are conditioned
 *       on making available complete source code of licensed works and
 *       modifications, which include larger works using a licensed work,
 *       under the same license.
 *     • Copyright and license notices must be preserved.
 *     • Contributors provide an express grant of patent rights.
 *     • When a modified version is used to provide a service over a
 *       network, the complete source code of the modified version must be made
 *       available.
 */
package nz.org.riskscape.engine.cli.tests;

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;

import org.junit.Test;

/**
 * Exercise the models-intro examples that are based on tsunami inundation of Upolu (a Samoan
 * Island).
 */
public class ModelsIntroTutorialTest extends BaseModelRunCommandTest {

  @Override
  public Path stdhome() {
    return Paths.get("..", "..", "examples", "models-intro");
  }

  @Test
  public void canRunBasicExposureModel() throws Exception {
    runCommand.modelId = "basic-exposure";
    runCommand.runnerOptions.format = "csv";

    runCommand.run();

    List<List<String>> results = openCsv("event_impact_table.csv", "exposure.the_geom",
        "exposure.Use_Cat", "exposure.Cons_Frame", "exposure.area", "exposure.perimeter",
        "hazard", "consequence");

    assertThat(results, hasSize(6260));
    // check an expected result
    assertThat(results, hasItem(Arrays.asList(
        "MULTIPOLYGON (((422215.4547116 8450108.50720521, 422213.271253114 8450120.49443072, "
        + "422223.958547166 8450121.5754324, 422225.236659099 8450110.37173975, "
        + "422215.4547116 8450108.50720521)))",
        "Residential", "Masonry", "121.22412109375", "44.16070725086322", "", "0")));
  }

  @Test
  public void canRunExposureReportingModel() throws Exception {
    runCommand.modelId = "exposure-reporting";
    runCommand.runnerOptions.format = "csv";

    runCommand.run();

    List<List<String>> results = openCsv("summary.csv", "Results", "Number_Exposed", "Total_buildings",
        "Max_hazard", "Average_hazard");
    assertThat(results, contains(
        Arrays.asList("Total", "2059", "6260", "8.218506813049316", "2.5090660887936354")
    ));

  }

  @Test
  public void canRunExposureReportingModelAndChangeTheHazard() throws Exception {
    runCommand.modelId = "exposure-reporting";
    runCommand.runnerOptions.format = "csv";
    runCommand.parameters = Arrays.asList("input-hazards.layer=data/MaxEnv_All_Scenarios_10m.tif");

    runCommand.run();

    List<List<String>> results = openCsv("summary.csv", "Results", "Number_Exposed", "Total_buildings",
        "Max_hazard", "Average_hazard");
    assertThat(results, contains(
        Arrays.asList("Total", "1568", "6260", "5.786825180053711", "1.6731144939454234")
    ));

  }

  @Test
  public void canRunExposureReportingModelAndChangeTheOutputGrouping() throws Exception {
    runCommand.modelId = "exposure-reporting";
    runCommand.runnerOptions.format = "csv";
    runCommand.parameters = Arrays.asList("report-summary.group-by[0]=exposure.Use_Cat");

    runCommand.run();

    List<List<String>> results = openCsv("summary.csv", "Use_Cat", "Number_Exposed", "Total_buildings",
        "Max_hazard", "Average_hazard");

    assertThat(results, containsInAnyOrder(
        Arrays.asList("Outbuilding", "623", "1343", "7.879426002502441", "2.331427180173883"),
        Arrays.asList("Residential", "930", "1862", "7.718549728393555", "2.2250018423603426"),
        Arrays.asList("Industrial", "6", "8", "3.821390390396118", "2.7654923796653748"),
        Arrays.asList("Religious - not verified", "0", "2", "", ""),
        Arrays.asList("Fale", "111", "146", "8.096136093139648", "2.7053862896051495"),
        Arrays.asList("Commercial", "14", "51", "7.13636589050293", "3.719742706843785"),
        Arrays.asList("Commercial - not verified", "1", "3", "1.5244611501693726", "1.5244611501693726"),
        Arrays.asList("Religious", "28", "60", "5.8724517822265625", "1.8323415092059545"),
        Arrays.asList("Hotel - not verified", "0", "1", "", ""),
        Arrays.asList("Community - not verified", "2", "6", "5.375617504119873", "5.0066187381744385"),
        Arrays.asList("Hotel", "198", "226", "8.218506813049316", "3.390313490472659"),
        Arrays.asList("Education", "12", "12", "5.941905975341797", "3.395870625972748"),
        Arrays.asList("Tourist Fale", "107", "157", "6.352619171142578", "3.8892281768477965"),
        Arrays.asList("Commericial - not verified", "1", "1", "5.397562026977539", "5.397562026977539"),
        Arrays.asList("Community", "23", "26", "6.209683418273926", "3.2658567169438237"),
        Arrays.asList("", "3", "2356", "1.9251530170440674", "1.3111796379089355")
    ));

  }

  @Test
  public void canRunExposureReportingModelAndFilterOnTheHazard() throws Exception {
    runCommand.modelId = "exposure-reporting";
    runCommand.runnerOptions.format = "csv";
    runCommand.parameters = Arrays.asList("report-summary.filter=hazard >= 0.5");

    runCommand.run();

    List<List<String>> results = openCsv("summary.csv", "Results", "Number_Exposed", "Total_buildings",
        "Max_hazard", "Average_hazard");
    assertThat(results, contains(
        Arrays.asList("Total", "1714", "1714", "8.218506813049316", "2.977457029677606")
    ));

  }

  @Test
  public void canRunExposureByRegionModel() throws Exception {
    // Note that this test uses http://risk.spc.int/geoserver to get the region data. If this test
    // breaks it could be because the server is down or maybe it is returning different data.
    // If the data does change then consider if the getting-started guide in the docs needs to be
    // updated to. It contains these expected results to.
    runCommand.modelId = "exposure-by-region";
    runCommand.runnerOptions.format = "csv";

    runCommand.run();

    List<List<String>> results = openCsv("event-impact.csv", "Region", "Exposed_Status", "Total_buildings");
    assertThat(results, contains(
        Arrays.asList("Aleipata Itupa i Lalo", "0", "332"),
        Arrays.asList("Aleipata Itupa i Lalo", "1", "531"),
        Arrays.asList("Aleipata Itupa i Luga", "0", "210"),
        Arrays.asList("Aleipata Itupa i Luga", "1", "345"),
        Arrays.asList("Anoamaa East", "0", "322"),
        Arrays.asList("Anoamaa West", "0", "32"),
        Arrays.asList("Falealili", "0", "1013"),
        Arrays.asList("Falealili", "1", "749"),
        Arrays.asList("Lepa", "0", "232"),
        Arrays.asList("Lepa", "1", "288"),
        Arrays.asList("Lotofaga", "0", "277"),
        Arrays.asList("Lotofaga", "1", "146"),
        Arrays.asList("Safata", "0", "595"),
        Arrays.asList("Siumu", "0", "682"),
        Arrays.asList("Vaa o Fonoti", "0", "405"),
        Arrays.asList("Vaimauga West", "0", "101")
    ));
  }

  @Test
  public void canRunExposureByRegionModelWithCustomFunction() throws Exception {
    // Note that this test uses http://risk.spc.int/geoserver to get the region data. If this test
    // breaks it could be because the server is down or maybe it is returning different data.
    // If the data does change then consider if the getting-started guide in the docs needs to be
    // updated to. It contains these expected results to.
    runCommand.modelId = "exposure-by-region";
    runCommand.parameters = Arrays.asList("analysis.function=exposure_status");
    runCommand.runnerOptions.format = "csv";

    runCommand.run();

    List<List<String>> results = openCsv("event-impact.csv", "Region", "Exposed_Status", "Total_buildings");
    assertThat(results, contains(
        Arrays.asList("Aleipata Itupa i Lalo", "Exposure >0.0m to <=1.0m", "89"),
        Arrays.asList("Aleipata Itupa i Lalo", "Exposure >1.0m to <=2.0m", "154"),
        Arrays.asList("Aleipata Itupa i Lalo", "Exposure >2.0m to <=3.0m", "166"),
        Arrays.asList("Aleipata Itupa i Lalo", "Exposure >3.0m", "122"),
        Arrays.asList("Aleipata Itupa i Lalo", "Not exposed", "332"),
        Arrays.asList("Aleipata Itupa i Luga", "Exposure >0.0m to <=1.0m", "74"),
        Arrays.asList("Aleipata Itupa i Luga", "Exposure >1.0m to <=2.0m", "21"),
        Arrays.asList("Aleipata Itupa i Luga", "Exposure >2.0m to <=3.0m", "42"),
        Arrays.asList("Aleipata Itupa i Luga", "Exposure >3.0m", "208"),
        Arrays.asList("Aleipata Itupa i Luga", "Not exposed", "210"),
        Arrays.asList("Anoamaa East", "Not exposed", "322"),
        Arrays.asList("Anoamaa West", "Not exposed", "32"),
        Arrays.asList("Falealili", "Exposure >0.0m to <=1.0m", "225"),
        Arrays.asList("Falealili", "Exposure >1.0m to <=2.0m", "166"),
        Arrays.asList("Falealili", "Exposure >2.0m to <=3.0m", "150"),
        Arrays.asList("Falealili", "Exposure >3.0m", "208"),
        Arrays.asList("Falealili", "Not exposed", "1013"),
        Arrays.asList("Lepa", "Exposure >0.0m to <=1.0m", "41"),
        Arrays.asList("Lepa", "Exposure >1.0m to <=2.0m", "31"),
        Arrays.asList("Lepa", "Exposure >2.0m to <=3.0m", "76"),
        Arrays.asList("Lepa", "Exposure >3.0m", "140"),
        Arrays.asList("Lepa", "Not exposed", "232"),
        Arrays.asList("Lotofaga", "Exposure >0.0m to <=1.0m", "44"),
        Arrays.asList("Lotofaga", "Exposure >1.0m to <=2.0m", "22"),
        Arrays.asList("Lotofaga", "Exposure >2.0m to <=3.0m", "38"),
        Arrays.asList("Lotofaga", "Exposure >3.0m", "42"),
        Arrays.asList("Lotofaga", "Not exposed", "277"),
        Arrays.asList("Safata", "Not exposed", "595"),
        Arrays.asList("Siumu", "Not exposed", "682"),
        Arrays.asList("Vaa o Fonoti", "Not exposed", "405"),
        Arrays.asList("Vaimauga West", "Not exposed", "101")
    ));
  }

}
