package be.msyben.vinylManager.tools.discogs;

import be.msyben.vinylManager.VinylManager;
import be.msyben.vinylManager.properties.Preferences;
import be.msyben.vinylManager.tools.Tools;
import be.msyben.vinylManager.tools.discogs.entities.FolderReleaseResponse;
import be.msyben.vinylManager.tools.discogs.entities.Inventory;
import be.msyben.vinylManager.tools.discogs.entities.Release;
import be.msyben.vinylManager.tools.discogs.entities.SearchResponse;
import be.msyben.vinylManager.tools.log.VinylManagerLogger;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.io.File;
import java.io.IOException;

public final class DiscogsDownloader {
    
    public static final String DISCOGS_API_URL="https://api.discogs.com";
    public static final String DISCOGS_URL = "http://www.discogs.com";
    
    private static final String USER_AGENT = "VinylManager/"+VinylManager.version+" + https://msyben.be/VinylManager";
    
    private static long lastCall = 0L;
    private static final long WAIT_TIME_MIN = 500L;
    private static final int MAX_RETRIES = 3;
    
    /*private static String getAuthorization() {
        String key = Preferences.getInstance().get(Preferences.DISCOGS_CONSUMER_TOKEN_KEY);
        String secret = Preferences.getInstance().get(Preferences.DISCOGS_CONSUMER_TOKEN_SECRET);
        if (key != null && secret != null) {
            return "Discogs key="+key+", secret="+secret;
        } else {
            return null;
        }
    }*/
    private static String getAuthorization() {
        String token = Preferences.getInstance().get(Preferences.DISCOGS_TOKEN);
        if (token != null && !token.isEmpty()) {
            //System.out.println("using token !!!");
            return "Discogs token=" + token;
        }
        
        String key = Preferences.getInstance().get(Preferences.DISCOGS_CONSUMER_TOKEN_KEY);
        String secret = Preferences.getInstance().get(Preferences.DISCOGS_CONSUMER_TOKEN_SECRET);
        if (key != null && secret != null) {
            return "Discogs key="+key+", secret="+secret;
        } else {
            return null;
        }
    }
    
    private static void waitForDiscogs() {
        long now = System.currentTimeMillis();
        long delta = now - lastCall;
        if (delta < WAIT_TIME_MIN) {
            long wait = WAIT_TIME_MIN-delta;
            try {
                Thread.sleep(wait);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            
        }
        lastCall = System.currentTimeMillis();
    }
    
    public static synchronized byte[] downloadURL(String url) {
        return downloadURL(url, 1);
    }
    public static synchronized byte[] downloadURL(String url, int retry) {
        if (retry > MAX_RETRIES) {
            return null;
        }
        waitForDiscogs();
        Client client = ClientBuilder.newClient();
        WebTarget target = client.target(url);
        try {
            String auth = getAuthorization();
            Response resp;
            if(auth != null) {
                resp = target.request(MediaType.APPLICATION_OCTET_STREAM_TYPE).header("User-Agent", USER_AGENT).header("Authorization", auth).get();
            } else {
                resp = target.request(MediaType.APPLICATION_OCTET_STREAM_TYPE).header("User-Agent", USER_AGENT).get();
            }
            if (resp.getStatus() == 200) {
                byte[] content = resp.readEntity(byte[].class);
                return content;
            } else if (resp.getStatus() == 503) {
                VinylManagerLogger.log("Erreur 503. Serveur Discogs trop occupé. On ré-essaie dans 10 secondes.");
                try {
                    Thread.sleep(10000L);
                } catch (Exception e) {
                    
                }
                return downloadURL(url, retry);
            } else {
                VinylManagerLogger.log("Erreur " + resp.getStatus() + " lors du téléchargement depuis Discogs");
                return downloadURL(url, retry+1);
            }
        } catch (Exception ex) {
            VinylManagerLogger.log("Erreur inatendue lors du téléchargement depuis Discogs : " + ex.getMessage());
            return downloadURL(url, retry+1);
        }
    }
    
    public static synchronized boolean downloadURL(String url, File destination) {
        byte[] content = downloadURL(url);
        if (content != null) {
            try {
                Tools.writeByteArrayToFile(destination, content);
            } catch (IOException ex) {
                VinylManagerLogger.log("Erreur lors de l'écriture dans le fichier : " + destination.getAbsolutePath());
            }
            return true;
        } else {
            return false;
        }
    }
    private static synchronized boolean downloadURL(String url, File destination, int retry) {
        if (retry > MAX_RETRIES) {
            return false;
        }
        waitForDiscogs();
        Client client = ClientBuilder.newClient();
        WebTarget target = client.target(url);
        try {
            String auth = getAuthorization();
            Response resp;
            if(auth != null) {
                resp = target.request(MediaType.APPLICATION_OCTET_STREAM_TYPE).header("User-Agent", USER_AGENT).header("Authorization", auth).get();
            } else {
                resp = target.request(MediaType.APPLICATION_OCTET_STREAM_TYPE).header("User-Agent", USER_AGENT).get();
            }
            if (resp.getStatus() == 200) {
                byte[] content = resp.readEntity(byte[].class);
                Tools.writeByteArrayToFile(destination, content);
                return true;
            } else if (resp.getStatus() == 503) {
                VinylManagerLogger.log("Erreur 503. Serveur Discogs trop occupé. On ré-essaie dans 10 secondes.");
                try {
                    Thread.sleep(10000L);
                } catch (Exception e) {
                    
                }
                return downloadURL(url, destination, retry);
            } else {
                VinylManagerLogger.log("Erreur " + resp.getStatus() + " lors du téléchargement depuis Discogs");
                return downloadURL(url, destination, retry+1);
            }
        } catch (Exception ex) {
            VinylManagerLogger.log("Erreur inatendue lors du téléchargement depuis Discogs : " + ex.getMessage());
            return downloadURL(url, destination, retry+1);
        }
    }
    
    public static synchronized SearchResponse searchByBarCode(String barcode) {
        return searchByBarCode(barcode, 1);
    }
    private static synchronized SearchResponse searchByBarCode(String barcode, int retry) {
        if (retry > MAX_RETRIES) {
            return null;
        }
        VinylManagerLogger.log("Téléchargement " + retry + "/" + MAX_RETRIES + " de la recherche par barcode " + barcode);
        
        waitForDiscogs();
        Client client = ClientBuilder.newClient();
        WebTarget target = client.target(DISCOGS_API_URL).path("database").path("search").queryParam("per_page", "100").queryParam("barcode", barcode).queryParam("type", "release");
        try {
            String auth = getAuthorization();
            Response resp;
            if(auth != null) {
                resp = target.request(MediaType.APPLICATION_JSON_TYPE).header("User-Agent", USER_AGENT).header("Authorization", auth).get();
            } else {
                resp = target.request(MediaType.APPLICATION_JSON_TYPE).header("User-Agent", USER_AGENT).get();
            }
            if (resp.getStatus() == 200) {
                return DiscogsJsonParser.getSearchResponse(resp.readEntity(String.class));
            } else if (resp.getStatus() == 503) {
                VinylManagerLogger.log("Erreur 503. Serveur Discogs trop occupé. On ré-essaie dans 10 secondes.");
                try {
                    Thread.sleep(10000L);
                } catch (Exception e) {
                    
                }
                return searchByBarCode(barcode, retry);
            } else {
                VinylManagerLogger.log("Erreur " + resp.getStatus() + " lors du téléchargement depuis Discogs");
                return searchByBarCode(barcode, retry+1);
            }
        } catch (Exception ex) {
            VinylManagerLogger.log("Erreur inatendue lors du téléchargement de la recherche depuis Discogs : " + ex.getMessage() + ". Probablement parsing JSON");
            return searchByBarCode(barcode, retry+1);
        }
    }
    
    
    public static synchronized SearchResponse searchByCatNo(String catno) {
        return searchByCatNo(catno, 1);
    }
    private static synchronized SearchResponse searchByCatNo(String catno, int retry) {
        if (retry > MAX_RETRIES) {
            return null;
        }
        VinylManagerLogger.log("Téléchargement " + retry + "/" + MAX_RETRIES + " de la recherche par catno " + catno);
        
        waitForDiscogs();
        Client client = ClientBuilder.newClient();
        WebTarget target = client.target(DISCOGS_API_URL).path("database").path("search").queryParam("per_page", "100").queryParam("catno", catno).queryParam("type", "release");
        try {
            String auth = getAuthorization();
            Response resp;
            if(auth != null) {
                resp = target.request(MediaType.APPLICATION_JSON_TYPE).header("User-Agent", USER_AGENT).header("Authorization", auth).get();
            } else {
                resp = target.request(MediaType.APPLICATION_JSON_TYPE).header("User-Agent", USER_AGENT).get();
            }
            if (resp.getStatus() == 200) {
                return DiscogsJsonParser.getSearchResponse(resp.readEntity(String.class));
            } else if (resp.getStatus() == 503) {
                VinylManagerLogger.log("Erreur 503. Serveur Discogs trop occupé. On ré-essaie dans 10 secondes.");
                try {
                    Thread.sleep(10000L);
                } catch (Exception e) {
                    
                }
                return searchByCatNo(catno, retry);
            } else {
                VinylManagerLogger.log("Erreur " + resp.getStatus() + " lors du téléchargement depuis Discogs");
                return searchByCatNo(catno, retry+1);
            }
        } catch (Exception ex) {
            VinylManagerLogger.log("Erreur inatendue lors du téléchargement de la recherche depuis Discogs : " + ex.getMessage() + ". Probablement parsing JSON");
            return searchByCatNo(catno, retry+1);
        }
    }
    
    public static synchronized SearchResponse searchByArtistTitle(String artist, String title) {
        return searchByArtistTitle(artist, title, 1);
    }
    private static synchronized SearchResponse searchByArtistTitle(String artist, String title, int retry) {
        if (retry > MAX_RETRIES) {
            return null;
        }
        VinylManagerLogger.log("Téléchargement " + retry + "/" + MAX_RETRIES + " de la recherche par artiste / title " + artist + " / " + title);
        
        waitForDiscogs();
        Client client = ClientBuilder.newClient();
        WebTarget target = client.target(DISCOGS_API_URL).path("database").path("search").queryParam("per_page", "100").queryParam("artist", artist).queryParam("release_title", title).queryParam("type", "release");
        try {
            String auth = getAuthorization();
            Response resp;
            if(auth != null) {
                resp = target.request(MediaType.APPLICATION_JSON_TYPE).header("User-Agent", USER_AGENT).header("Authorization", auth).get();
            } else {
                resp = target.request(MediaType.APPLICATION_JSON_TYPE).header("User-Agent", USER_AGENT).get();
            }
            if (resp.getStatus() == 200) {
                return DiscogsJsonParser.getSearchResponse(resp.readEntity(String.class));
            } else if (resp.getStatus() == 503) {
                VinylManagerLogger.log("Erreur 503. Serveur Discogs trop occupé. On ré-essaie dans 10 secondes.");
                try {
                    Thread.sleep(10000L);
                } catch (Exception e) {
                    
                }
                return searchByArtistTitle(artist, title, retry);
            } else {
                VinylManagerLogger.log("Erreur " + resp.getStatus() + " lors du téléchargement depuis Discogs");
                return searchByArtistTitle(artist, title, retry+1);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            VinylManagerLogger.log("Erreur inatendue lors du téléchargement de la recherche depuis Discogs : " + ex.getMessage() + ". Probablement parsing JSON");
            return searchByArtistTitle(artist, title, retry+1);
        }
    }
    
    public static synchronized Release getRelease(long releaseId) {
        Release found = getRelease(releaseId, 1);
        return found;
    }
    
    private static synchronized Release getRelease(long releaseId, int retry) {
        
        if (retry > MAX_RETRIES) {
            return null;
        }
        VinylManagerLogger.log("Téléchargement " + retry + "/" + MAX_RETRIES + " de la release " + releaseId);
        
        waitForDiscogs();
        Client client = ClientBuilder.newClient();
        WebTarget target = client.target(DISCOGS_API_URL).path("releases").path(""+releaseId);
        
        try {
            String auth = getAuthorization();
            Response resp;
            if(auth != null) {
                resp = target.request(MediaType.APPLICATION_JSON_TYPE).header("User-Agent", USER_AGENT).header("Authorization", auth).get();
            } else {
                resp = target.request(MediaType.APPLICATION_JSON_TYPE).header("User-Agent", USER_AGENT).get();
            }
            if (resp.getStatus() == 200) {
                String response = resp.readEntity(String.class);
                //System.out.println(response);
                return DiscogsJsonParser.getRelease(response);
            } else if (resp.getStatus() == 503) {
                VinylManagerLogger.log("Erreur 503. Serveur Discogs trop occupé. On ré-essaie dans 10 secondes.");
                try {
                    Thread.sleep(10000L);
                } catch (Exception e) {
                    
                }
                return getRelease(releaseId, retry);
            } else {
                VinylManagerLogger.log("Erreur " + resp.getStatus() + " lors du téléchargement depuis Discogs");
                return getRelease(releaseId, retry+1);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            VinylManagerLogger.log("Erreur inatendue lors du téléchargement de la release depuis Discogs : " + ex.getMessage() + ". Probablement parsing JSON");
            return getRelease(releaseId, retry+1);
        }
    }
    
    public static synchronized Inventory getInventory(String inventory) {
        return getInventory(inventory, 1);
    }
    public static synchronized Inventory getInventory(String inventory, int page) {
        return getInventory(inventory, page, 1);
    }
    private static synchronized Inventory getInventory(String inventory, int page, int retry) {
        if (retry > MAX_RETRIES) {
            return null;
        }
        VinylManagerLogger.log("Téléchargement " + retry + "/" + MAX_RETRIES + " de la page " + page + " de l'inventory " + inventory);
        
        waitForDiscogs();
        Client client = ClientBuilder.newClient();
        WebTarget target = client.target(DISCOGS_API_URL).path("users").path(inventory).path("inventory").queryParam("per_page", "100").queryParam("page", ""+page);
        
        try {
            String auth = getAuthorization();
            Response resp;
            if(auth != null) {
                resp = target.request(MediaType.APPLICATION_JSON_TYPE).header("User-Agent", USER_AGENT).header("Authorization", auth).get();
            } else {
                resp = target.request(MediaType.APPLICATION_JSON_TYPE).header("User-Agent", USER_AGENT).get();
            }
            if (resp.getStatus() == 200) {
                return DiscogsJsonParser.getInventory(resp.readEntity(String.class));
            } else if (resp.getStatus() == 503) {
                VinylManagerLogger.log("Erreur 503. Serveur Discogs trop occupé. On ré-essaie dans 10 secondes.");
                try {
                    Thread.sleep(10000L);
                } catch (Exception e) {
                    
                }
                return getInventory(inventory, page, retry);
            } else {
                VinylManagerLogger.log("Erreur " + resp.getStatus() + " lors du téléchargement depuis Discogs");
                return getInventory(inventory, page, retry+1);
            }
        } catch (Exception ex) {
            VinylManagerLogger.log("Erreur inatendue lors du téléchargement du listing depuis Discogs : " + ex.getMessage() + ". Probablement parsing JSON");
            return getInventory(inventory, page, retry+1);
        }
    }
    
    
    
    public static synchronized FolderReleaseResponse getFolderReleases(String username, int folderId) {
        return getFolderReleases(username, folderId, 1);
    }
    public static synchronized FolderReleaseResponse getFolderReleases(String username, int folderId, int page) {
        return getFolderReleases(username, folderId, page, 1);
    }
    private static synchronized FolderReleaseResponse getFolderReleases(String username, int folderId, int page, int retry) {
        if (retry > MAX_RETRIES) {
            return null;
        }
        VinylManagerLogger.log("Téléchargement " + retry + "/" + MAX_RETRIES + " de la page " + page + " du folder " + folderId + " de l'utilisateur " + username);
        
        waitForDiscogs();
        Client client = ClientBuilder.newClient();
        WebTarget target = client.target(DISCOGS_API_URL)
                .path("users")
                .path(username)
                .path("collection")
                .path("folders")
                .path(""+folderId)
                .path("releases")
                .queryParam("per_page", "100")
                .queryParam("page", ""+page);
        
        try {
            String auth = getAuthorization();
            Response resp;
            if(auth != null) {
                resp = target.request(MediaType.APPLICATION_JSON_TYPE).header("User-Agent", USER_AGENT).header("Authorization", auth).get();
            } else {
                resp = target.request(MediaType.APPLICATION_JSON_TYPE).header("User-Agent", USER_AGENT).get();
            }
            if (resp.getStatus() == 200) {
                return DiscogsJsonParser.getFolderReleaseResponse(resp.readEntity(String.class));
            } else if (resp.getStatus() == 503) {
                VinylManagerLogger.log("Erreur 503. Serveur Discogs trop occupé. On ré-essaie dans 10 secondes.");
                try {
                    Thread.sleep(10000L);
                } catch (Exception e) {
                    
                }
                return getFolderReleases(username, folderId, page, retry);
            } else {
                VinylManagerLogger.log("Erreur " + resp.getStatus() + " lors du téléchargement depuis Discogs");
                System.out.println(resp.readEntity(String.class));
                return getFolderReleases(username, folderId, page, retry+1);
            }
        } catch (Exception ex) {
            VinylManagerLogger.log("Erreur inatendue lors du téléchargement du folder releases depuis Discogs : " + ex.getMessage() + ". Probablement parsing JSON");
            return getFolderReleases(username, folderId, page, retry+1);
        }
    }
    
}
