package com.kpl.CourierMgmt.FeatureTests;

import com.kpl.CourierMgmt.CourierManager.CourierBooking;
import com.kpl.CourierMgmt.CourierManager.Scheduler;
import com.kpl.CourierMgmt.CourierManager.SchedulerFactory;

import cucumber.api.java.en.Given;
import cucumber.api.java.en.When;
import cucumber.api.java.en.Then;

import static org.junit.jupiter.api.Assertions.*;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import cucumber.api.PendingException;
import cucumber.api.DataTable;

public class CourierBookingSteps {
	
    Hashtable<String, Object> context = new Hashtable<String, Object>();
    
    private double fromInts(int exp, int mant) {
        double frac = mant;
        while(frac >= 1.0)
            frac /= 10;
        return exp + frac;
    }
	@Given("^I am using the default courier manager$")
	public void i_am_using_the_default_courier_manager() throws Exception {
	    // Write code here that turns the phrase above into concrete actions
		Scheduler scheduler = (new SchedulerFactory()).CreateScheduler();
        context.put("scheduler", scheduler);

	}

	@Given("^I have a (\\d+)\\.(\\d+) kg package to go from \"([^\"]*)\" to \"([^\"]*)\"$")
	public void i_have_a_kg_package_to_go_from_to(int arg1, int arg2, String arg3, String arg4) throws Exception {
	    // Write code here that turns the phrase above into concrete actions
		double weight = fromInts(arg1,  arg2);
        context.put("weight", weight);
        context.put("origin", arg3);
        context.put("destination", arg4);
	}

	@When("^I book a courier$")
	public void i_book_a_courier() throws Exception {
	    // Write code here that turns the phrase above into concrete actions
		Scheduler scheduler = (Scheduler)context.get("scheduler");
        CourierBooking booking = scheduler.MakeBooking(
            "Test shipment", 
            (String)context.get("origin"), 
            (String)context.get("destination"), 
            (double)context.get("weight"));
        context.put("booking", booking);
	}

	@Then("^the booking is successful$")
	public void the_booking_is_successful() throws Exception {
	    // Write code here that turns the phrase above into concrete actions
		assertNotNull(context.get("booking"));
	}

	@Then("^the distance the courier will carry is (\\d+)\\.(\\d+) km$")
	public void the_distance_the_courier_will_carry_is_km(int arg1, int arg2) throws Exception {
	    // Write code here that turns the phrase above into concrete actions
		CourierBooking booking = (CourierBooking)context.get("booking");
        assertEquals(fromInts(arg1, arg2), booking.GetDistance(), 0.01);
	}
	
	@Given("^I have the following deliveries to schedule$")
	public void i_have_the_following_deliveries_to_schedule(DataTable arg1) throws Exception {
	    // Write code here that turns the phrase above into concrete actions
	    // For automatic transformation, change DataTable to one of
	    // List<YourType>, List<List<E>>, List<Map<K,V>> or Map<K,V>.
	    // E,K,V must be a scalar (String, Integer, Date, enum etc)
		context.put("deliveries", arg1);
	}

	@When("^I make these bookings$")
	public void i_make_these_bookings() throws Exception {
	    // Write code here that turns the phrase above into concrete actions
		
		DataTable table = (DataTable)context.get("deliveries");
		List<Map<String, String>> rows = table.asMaps(String.class, String.class);
		List<Delivery> deliveries = new ArrayList<Delivery>();
		for(Map<String, String> m : rows) {
			Delivery d = new Delivery();
			d.Weight = Double.parseDouble(m.get("Weight"));
			d.Origin = m.get("Origin");
			d.Destination = m.get("Destination");
			deliveries.add(d);
		}
        List<CourierBooking> bookings = new ArrayList<CourierBooking>();
        Scheduler scheduler = (Scheduler)context.get("scheduler");
        for(Delivery d : deliveries)
            bookings.add(scheduler.MakeBooking
                ("A shipment", d.Origin, d.Destination, d.Weight));
        context.put("bookings", bookings);
	}

	@Then("^the couriers, distances and prices are$")
	public void the_couriers_distances_and_prices_are(DataTable arg1) throws Exception {
	    // Write code here that turns the phrase above into concrete actions
	    // For automatic transformation, change DataTable to one of
	    // List<YourType>, List<List<E>>, List<Map<K,V>> or Map<K,V>.
	    // E,K,V must be a scalar (String, Integer, Date, enum etc)
		
		Scheduler scheduler = (Scheduler)context.get("scheduler");
        List<CourierBooking> bookings = (List<CourierBooking>)(context.get("bookings"));
        List<List<String>> rawTable = arg1.raw();
        for(int i = 1; i < rawTable.size(); i++) 
        {
            CourierBooking b = bookings.get(i-1);
            List<String> row = rawTable.get(i);
            assertEquals(row.get(0), scheduler.DetailsFromBooking(b).Courier.Name);
            assertEquals(Double.parseDouble(row.get(1)), b.GetDistance(), 0.01);
            assertEquals(Integer.parseInt(row.get(2)), b.GetFare());
        }
	}
}
