package ch.unisg.tapas.common;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import ch.unisg.tapas.auctionhouse.adapter.out.web.AuctionHouseDiscoveryHttpAdapter;
import ch.unisg.tapas.auctionhouse.application.port.out.AuctionHouseDiscoveryPort;
import ch.unisg.tapas.auctionhouse.domain.AuctionHouseDiscoveryInformation;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.List;

/**
 * Class that wraps up the resource directory used to discover auction houses in Week 6.
 */
public class AuctionHouseResourceDirectory {
    private final URI rdEndpoint;

    /**
     * Constructs a resource directory for auction house given a known URI.
     *
     * @param rdEndpoint the based endpoint of the resource directory
     */
    public AuctionHouseResourceDirectory(URI rdEndpoint) {
        this.rdEndpoint = rdEndpoint;
    }

    private AuctionHouseDiscoveryPort auctionHouseDiscoveryport = new AuctionHouseDiscoveryHttpAdapter();

    private List<AuctionHouseDiscoveryInformation> auctionHouseEndpoints = new ArrayList<>();

    // List to keep track of already fetched endpoints
    private List<URI> fetchedEndpoints = new ArrayList<>();

    /**
     * Retrieves the endpoints of all auctions houses registered with this directory.
     * @return
     */
    public List<AuctionHouseDiscoveryInformation> retrieveAuctionHouseEndpoints() {

        fetchedEndpoints.clear();
        auctionHouseEndpoints.clear();

        fetchedEndpoints.add(rdEndpoint);
        // Start recusive fetching of auctionhouses
        fetchEndpoints(getInformation(rdEndpoint));

        return auctionHouseEndpoints;
    }

    // Recursive function to fetch all endpoints
    private void fetchEndpoints(List<AuctionHouseDiscoveryInformation> auctionHouses) {

        for (AuctionHouseDiscoveryInformation ah : auctionHouses) {
            if (!fetchedEndpoints.contains(ah.getAuctionHouseUri().getValue())) {
                fetchedEndpoints.add(ah.getAuctionHouseUri().getValue());
                fetchEndpoints(getInformation(ah.getAuctionHouseUri().getValue()));
            }
        }

    }

    private List<AuctionHouseDiscoveryInformation> getInformation(URI uri) {
        List<AuctionHouseDiscoveryInformation> discoveries;
        try {
            discoveries = auctionHouseDiscoveryport.fetchAuctionHouseInformation(new URI(uri.toString() + "/discovery/"));
            outerloop:
            for (AuctionHouseDiscoveryInformation discovery : discoveries) {
                for (AuctionHouseDiscoveryInformation endpoint : auctionHouseEndpoints) {
                    // Check if discovery is already in our endpoint list
                    if (endpoint.getAuctionHouseUri().getValue().toString().equals(discovery.getAuctionHouseUri().getValue().toString())) {
                        // Check if the new discovery is more recent than the current
                        if (endpoint.getTimeStamp().getValue().before(discovery.getTimeStamp().getValue())) {
                            // Endpoint information is older. Remove and add the new discovery to the list
                            auctionHouseEndpoints.remove(endpoint);
                            break;
                        } else {
                            continue outerloop;
                        }
                    }
                }
                auctionHouseEndpoints.add(discovery);
            }
            return discoveries;
        } catch (URISyntaxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // When an error happens return empty list
        return new ArrayList<AuctionHouseDiscoveryInformation>();
    }
}
