package Team5.SmartTowns;

import Team5.SmartTowns.data.Location;
import Team5.SmartTowns.data.Trail;
import Team5.SmartTowns.landmarks.Landmarks;
import Team5.SmartTowns.placeswithcoordinates.LocationsCoordinates;
import Team5.SmartTowns.placeswithcoordinates.PlacesController;
import Team5.SmartTowns.placeswithcoordinates.TownWithTrails;
import jakarta.validation.Path;
import jakarta.validation.constraints.AssertTrue;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
//import org.junit.platform.engine.support.hierarchical.Node;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;

import java.util.*;

import static java.util.Arrays.compare;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;

import jakarta.validation.ConstraintViolation; //- (https://davidvlijmincx.com/posts/test-annotation-validation/)
import jakarta.validation.Validation;
import jakarta.validation.Validator;

import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class JUnitSimpleTests {

    private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

    @Test
public void landmarkJakartaValidationTest() {
        Landmarks landmark = new Landmarks("99", 1, "MockLandmark", "Mock@Mock2.com",
                "MockLandmarkDesc", "MockRisca", "MockImage");
        Set<ConstraintViolation<Landmarks>> violations = validator.validate(landmark);
        //nothing wrong with chosen Landmark wrt violations
        assertTrue(violations.isEmpty());

        //test landmarkName @NotEmpty() verification.
        landmark.setLandmarkName("");
        Set<ConstraintViolation<Landmarks>> violationsName = validator.validate(landmark);
        assertFalse(violationsName.isEmpty());
        //verify violation message matches correct variable and both are correct
        List<String> fieldName = violationsName.stream().map((ConstraintViolation::getPropertyPath)).map(Object::toString).toList();
        List<String> fieldNameMessage = violationsName.stream().map((ConstraintViolation::getMessage)).map(Object::toString).toList();
        assertEquals(fieldName.get(0), "landmarkName");
        assertEquals(fieldNameMessage.get(0), "You must type in a username."); //assert
        landmark.setLandmarkName("MockName");
        //test @NotEmpty on email variable.
        landmark.setLandmarkEmail("");
        Set<ConstraintViolation<Landmarks>> violationsEmailOne = validator.validate(landmark);
        List<String> fieldEmailEmpty = violationsEmailOne.stream().map((ConstraintViolation::getPropertyPath)).map(Object::toString).toList();
        List<String> fieldEmailMessageEmpty = violationsEmailOne.stream().map((ConstraintViolation::getMessage)).map(Object::toString).toList();
        assertEquals(fieldEmailEmpty.get(0), "landmarkEmail");
        assertEquals(fieldEmailMessageEmpty.get(0), "You must attach a contact address.");
        //Test @Email() verification
        landmark.setLandmarkEmail("NotValidEmail");
        Set<ConstraintViolation<Landmarks>> violationsEmailTwo = validator.validate(landmark);
        List<String> fieldEmailWrong = violationsEmailTwo.stream().map((ConstraintViolation::getPropertyPath)).map(Object::toString).toList();
        List<String> fieldEmailMessageWrong = violationsEmailTwo.stream().map((ConstraintViolation::getMessage)).map(Object::toString).toList();
        assertEquals(fieldEmailWrong.get(0), "landmarkEmail");
        assertEquals(fieldEmailMessageWrong.get(0), "You must attach a valid contact address.");
    }









    @Test
    @Order(1)
    public void landmarksTest(){ // generic for all landmarks, trails+dragons tale
        Landmarks landmark = new Landmarks("99",1,"MockLandmark","Mock@Mock2.com",
                "MockLandmarkDesc","MockRisca","MockImage");
        assertEquals(landmark.getTrailID(),"99");
        assertEquals(landmark.getLandmarkID(),1);
        assertEquals(landmark.getLandmarkName(),"MockLandmark");
        assertEquals(landmark.getLandmarkEmail(),"Mock@Mock2.com");
        assertEquals(landmark.getLandmarkDescription(),"MockLandmarkDesc");
        assertEquals(landmark.getLandmarkLocation(),"MockRisca");
        assertEquals(landmark.getLandmarkPicture(),"MockImage");

        landmark.setTrailID("66");
        assertEquals(landmark.getTrailID(),"66");
        landmark.setLandmarkID(2);
        assertEquals(landmark.getLandmarkID(),2);
        landmark.setLandmarkName("MockChange");
        assertEquals(landmark.getLandmarkName(),"MockChange");
        landmark.setLandmarkEmail("Mock@Change2.co.uk");
        assertEquals(landmark.getLandmarkEmail(),"Mock@Change2.co.uk");
        landmark.setLandmarkDescription("MockDescChange");
        assertEquals(landmark.getLandmarkDescription(),"MockDescChange");
        landmark.setLandmarkLocation("MockLondon");
        assertEquals(landmark.getLandmarkLocation(),"MockLondon");
        landmark.setLandmarkPicture("MockPainting");
        assertEquals(landmark.getLandmarkPicture(),"MockPainting");

    }

    @Test
    @Order(2)
    public void locationsTest(){ //specific for trail locations
        Location location = new Location(1,"MockLocation", "Mock@Test.co.uk",
                "MockDescription","MockCaerphilly","99",false);
        assertEquals(location.getLocationID(),1);
        assertEquals(location.getLocationName(),"MockLocation");
        assertEquals(location.getLocationEmail(),"Mock@Test.co.uk");
        assertEquals(location.getLocationDescription(),"MockDescription");
        assertEquals(location.getLocationPlace(),"MockCaerphilly");
        assertEquals(location.getLocationTrailID(),"99");
        assertEquals(location.isLocationApproved(),false);

        location.setLocationID(2);
        assertEquals(location.getLocationID(),2);
        location.setLocationName("MockChange");
        assertEquals(location.getLocationName(),"MockChange");
        location.setLocationEmail("Mock@Change.com");
        assertEquals(location.getLocationEmail(),"Mock@Change.com");
        location.setLocationDescription("MockTree");
        assertEquals(location.getLocationDescription(),"MockTree");
        location.setLocationPlace("MockCardiff");
        assertEquals(location.getLocationPlace(),"MockCardiff");
        location.setLocationTrailID("66");
        assertEquals(location.getLocationTrailID(),"66");
        location.setLocationApproved(true);
        assertEquals(location.isLocationApproved(),true);



    }





    @Test
    @Order(3)
    public void locationsCoordinatesTest(){
        LocationsCoordinates locCoord = new LocationsCoordinates(1,51.57756,-3.22002);
        assertEquals(locCoord.getLocationID(),1);
        assertEquals(locCoord.getLocationCoordsLat(),51.57756);
        assertEquals(locCoord.getLocationCoordsLong(),-3.22002);

        locCoord.setLocationID(2);
        assertEquals(2,locCoord.getLocationID());
        locCoord.setLocationCoordsLat(66.00);
        assertEquals(66,locCoord.getLocationCoordsLat());
        locCoord.setLocationCoordsLong(-5.00);
        assertEquals(-5,locCoord.getLocationCoordsLong());
    }

    @Test
    public void trailTest(){
        Trail trail = new Trail(101L, "MockTrail", "0101");
        assertEquals(trail.getTrailsId(),101);
        assertEquals(trail.getTrailName(),"MockTrail");
        assertEquals(trail.getTrailNumber(),"0101");
        assertTrue(trail.getTrailsId()<200);
        assertTrue(trail.getTrailsId()>100);

        trail.setTrailsId(202L);
        assertEquals(trail.getTrailsId(),202);
        trail.setTrailName("MockChange");
        assertEquals(trail.getTrailName(),"MockChange");
        trail.setTrailNumber("99");
        assertEquals(trail.getTrailNumber(),"99");

    }


    @Test
    public void townWithTrailsTest(){
        TownWithTrails townTrail = new TownWithTrails("MockCaerphilly","51.57903","-3.22075",
                "51.60418", "51.55093", "-3.25222", "-3.17696");
        assertEquals(townTrail.getTownName(),"MockCaerphilly");
        assertEquals(townTrail.getTownCentreCoordsLat(),"51.57903");
        assertEquals(townTrail.getTownCentreCoordsLong(),"-3.22075");
        assertEquals(townTrail.getTownUppermostCoordsLat(),"51.60418");
        assertEquals(townTrail.getTownLowermostCoordsLat(),"51.55093");
        assertEquals(townTrail.getTownLeftmostCoordsLong(),"-3.25222");
        assertEquals(townTrail.getTownRightmostCoordsLong(),"-3.17696");

        townTrail.setTownName("MockChangeTown");
        assertEquals(townTrail.getTownName(),"MockChangeTown");
        townTrail.setTownCentreCoordsLat("50.00");
        assertEquals(townTrail.getTownCentreCoordsLat(),"50.00");
        townTrail.setTownCentreCoordsLong("-5.00");
        assertEquals(townTrail.getTownCentreCoordsLong(),"-5.00");
        townTrail.setTownUppermostCoordsLat("55.00");
        assertEquals(townTrail.getTownUppermostCoordsLat(),"55.00");
        townTrail.setTownLowermostCoordsLat("45.00");
        assertEquals(townTrail.getTownLowermostCoordsLat(),"45.00");
        townTrail.setTownLeftmostCoordsLong("-6.00");
        assertEquals(townTrail.getTownLeftmostCoordsLong(),"-6.00");
        townTrail.setTownRightmostCoordsLong("-4.00");
        assertEquals(townTrail.getTownRightmostCoordsLong(),"-4.00");


    }

    @Test
    @Order(4)
    public void reorderingLocationCoordsListToMatchIDWithLocationListTest(){
        List<Location> locList = new ArrayList<>(); /// trail location list, w/ ID as expected from DB output
        locList.add(new Location(1,"MockLocation", "Mock@Test.co.uk",
                "MockDescription","MockCaerphilly","99",false));
        locList.add(new Location(2,"MockLocation2", "Mock2@Test.co.uk",
                "MockDescription2","MockCaerphilly","99",false));
        locList.add(new Location(3,"MockLocation3", "Mock3@Test.co.uk",
                "MockDescription","MockCaerphilly","99",false));

        List<LocationsCoordinates> locCoordsListOriginal = new ArrayList<>(); // /// trail locationCoordinates list, w/ ID as expected from DB output, locationID is foreign key.
        locCoordsListOriginal.add(new LocationsCoordinates(3,51.57756,-3.22002));
        locCoordsListOriginal.add(new LocationsCoordinates(1,51.57756,-3.22002));
        locCoordsListOriginal.add(new LocationsCoordinates(2,51.57756,-3.22002));

        List<LocationsCoordinates> locCoordsReorder = new ArrayList<>(); // Same list as above, repeated to allow comparison w/ original
        locCoordsReorder.add(new LocationsCoordinates(3,51.57756,-3.22002));
        locCoordsReorder.add(new LocationsCoordinates(1,51.57756,-3.22002));
        locCoordsReorder.add(new LocationsCoordinates(2,51.57756,-3.22002));

        PlacesController.reorderCoordsWRTLocations(locCoordsReorder); // second list reordered to be ascending locationID order to match trail location ID list.
        assertEquals(locList.get(0).getLocationID(),locCoordsReorder.get(0).getLocationID());
        assertEquals(locList.get(2).getLocationID(),locCoordsReorder.get(2).getLocationID());
        assertNotEquals(locList.get(1).getLocationID(),locCoordsReorder.get(2).getLocationID());
        assertNotEquals(locList.get(0).getLocationID(),locCoordsListOriginal.get(0).getLocationID());
    }

    }


//todo test town?