package be.msyben.vinylManager.tools.discogs;

import be.msyben.vinylManager.entities.Album;
import be.msyben.vinylManager.entities.Disque;
import be.msyben.vinylManager.entities.Image;
import be.msyben.vinylManager.entities.Titre;
import be.msyben.vinylManager.exceptions.VinylManagerException;
import be.msyben.vinylManager.properties.Language;
import be.msyben.vinylManager.properties.Preferences;
import be.msyben.vinylManager.properties.Support;
import be.msyben.vinylManager.properties.Taille;
import be.msyben.vinylManager.properties.Vitesse;
import be.msyben.vinylManager.tools.Tools;
import be.msyben.vinylManager.tools.WaitThread;
import be.msyben.vinylManager.tools.discogs.entities.FolderRelease;
import be.msyben.vinylManager.tools.discogs.entities.FolderReleaseResponse;
import be.msyben.vinylManager.tools.discogs.entities.Format;
import be.msyben.vinylManager.tools.discogs.entities.Release;
import be.msyben.vinylManager.tools.discogs.entities.SearchResponse;
import be.msyben.vinylManager.tools.discogs.entities.SearchResult;
import be.msyben.vinylManager.tools.discogs.entities.Track;
import be.msyben.vinylManager.tools.log.VinylManagerLogger;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import org.apache.commons.lang3.StringUtils;



/**
 * Recherche avec Discogs.
 *
 * @author Mathieu Syben
 */
public final class DiscogsSearch {

    private DiscogsSearch() {
    }
    
    
    /**
     * Effectue une recherche depuis une référence.
     *
     * @param reference la référence à rechercher.
     * @return Une liste de résultat.
     * @throws VinylManagerException En cas d'erreur.
     */
    public static List<DiscogsSearchResult> searchRef(String reference, JFrame parent) throws VinylManagerException {
        return convert(DiscogsDownloader.searchByCatNo(reference));
    }
    
    /**
     * Effectue une recherche depuis un code barre.
     *
     * @param barcode le barcode à rechercher.
     * @return Une liste de résultat.
     * @throws VinylManagerException En cas d'erreur.
     */
    public static List<DiscogsSearchResult> searchBarcode(String barcode, JFrame parent) throws VinylManagerException {
        return convert(DiscogsDownloader.searchByBarCode(barcode));
    }
    
    /**
     * Effectue une recherche avec un nom d'artiste et un titre.
     *
     * @param artist Le nom de l'artiste.
     * @param titre Le titre de l'album.
     * @return Une liste de résultats.
     * @throws VinylManagerException En cas d'erreur.
     */
    public static List<DiscogsSearchResult> searchArtist(String artist, String titre, JFrame parent) throws VinylManagerException {
        return convert(DiscogsDownloader.searchByArtistTitle(artist, titre));
    }
    
    private static List<DiscogsSearchResult> convert(SearchResponse search) {
        List<DiscogsSearchResult> ret = new ArrayList<DiscogsSearchResult>();
        if (search != null && search.getResults() != null) {
            for (SearchResult result : search.getResults()) {
                DiscogsSearchResult dsr = new DiscogsSearchResult();
                dsr.setAnnee(result.getYear()+"");
                dsr.setDiscogsId(result.getId());
                dsr.setFormat(result.getFormatString());
                dsr.setGenre(result.getGenreString());
                dsr.setLabel(result.getLabelString());
                dsr.setPays(result.getCountry());
                dsr.setReference(result.getCatno());
                dsr.setResourceUrl(result.getResource_url());
                dsr.setThumb(result.getThumb());
                dsr.setTitre(result.getTitle());
                ret.add(dsr);
            } 
        }
        return ret;
    }
    
    /**
     * Récupère un objet Album lié à un résultat.
     *
     * @param discogsId l'identifiant Discogs de l'album.
     * @return L'album lié.
     * @throws VinylManagerException En cas d'erreur.
     */
    public static Album getAlbum(long discogsId, JFrame parent) throws VinylManagerException {
        Release r = DiscogsDownloader.getRelease(discogsId);
        if (r == null) {
            throw new VinylManagerException(Language.getInstance().get("discogs.download.error"));
        }
        return getReleaseAsAlbum(r);
    }
    private static Album getReleaseAsAlbum(Release r) throws VinylManagerException {
        Album album  = new Album();
        String artist = r.getArtistsString();
        boolean compil = artist.equalsIgnoreCase("various");
        if (compil) {
            album.setCompilation(true);
        } else {
            album.setArtiste(artist);
        }
        
        album.setDiscogsId(""+r.getId());
        album.setTitre(r.getTitle());
        album.setAnnee(""+r.getYear());
        if (r.getGenres() != null && r.getGenres().length > 0) {
            album.setGenre(r.getGenres()[0]);
        }
        album.setReference(r.getCatNo());
        if (r.getLabels() != null && r.getLabels().length > 0 && r.getLabels()[0].getName() != null) {
            album.setEditeur(r.getLabels()[0].getName());
        }
        album.setPays(r.getCountry());
        
        String imageUrl = r.getFirstImageUrl();
        if (imageUrl != null && !imageUrl.isEmpty()){
            byte[] img = DiscogsDownloader.downloadURL(imageUrl);
            if (img != null && img.length > 0) {
                img = Tools.convertToRGB(img);
                if (img != null && img.length > 0) {
                    boolean resize = Preferences.getInstance().get(Preferences.RESIZE_PICTURES, "Y").equals("Y");
                    if (resize) {
                        img = Tools.getReducedImage(img);
                    }

                    Image imaObj = new Image();
                    imaObj.setContenu(img);
                    imaObj.setNom(imageUrl.substring(imageUrl.lastIndexOf("/")));
                    album.setImage(imaObj);
                }
            }
        }
        String notes = r.getNotes();
        if (notes == null) {
            notes = "";
        }
        album.setCommentaire(DiscogsDownloader.DISCOGS_URL+"/release/"+r.getId() + "\r\n" + notes);
        
        Format[] formats = r.getFormats();
        if (formats != null && formats.length > 0) {
            Format format = formats[0];
            String formatName = format.getName();
            if (formatName.equalsIgnoreCase("Vinyl")) {
                album.setSupport(Support.vinyl.getId());
            } else if (formatName.equalsIgnoreCase("SACD")) {
                album.setSupport(Support.sacd.getId());
            } else if (formatName.equalsIgnoreCase("CD")) {
                album.setSupport(Support.cd.getId());
            } else if (formatName.equalsIgnoreCase("Cassette")) {
                album.setSupport(Support.k7.getId());
            } else if (formatName.equalsIgnoreCase("DAT")) {
                album.setSupport(Support.k7.getId());
            } else if (formatName.equalsIgnoreCase("Minidisc")) {
                album.setSupport(Support.md.getId());
            } else {
                album.setSupport(Support.autre.getId());
            }
        }
        
        
        boolean isOneSide;
        switch (Support.getSupport(album.getSupport())) {
            case cd:
            case bluray:
            case md:
            case vhs: isOneSide = true; break;
            default: isOneSide = false; break;
        }
        
        // Test avec 8876563 et avec 631721 et avec 8052861
        for(Disque d : getDisques(r.getTracklist(), isOneSide, compil)) {
            album.addDisque(d);
        }
        
        if (Support.getSupport(album.getSupport()) == Support.vinyl || Support.getSupport(album.getSupport()) == Support.schellack) {
            if (formats != null && formats.length > 0) {
                Format format = formats[0];
                String[] descriptions = format.getDescriptions();
                if (descriptions != null) {
                    if (contains(descriptions, "LP")) {
                        for (Disque d : album.getDisques()) {
                            d.setVitesse(Vitesse.vitesse33.getId());
                            d.setTaille(Taille.taille30.getId());
                        }
                    } else if (contains(descriptions, "Single")) {
                        for (Disque d : album.getDisques()) {
                            d.setVitesse(Vitesse.vitesse45.getId());
                            d.setTaille(Taille.taille17.getId());
                        }
                    } else if (contains(descriptions, "Maxi-Single")) {
                        for (Disque d : album.getDisques()) {
                            d.setVitesse(Vitesse.vitesse45.getId());
                            d.setTaille(Taille.taille30.getId());
                        }
                    } else {
                        if (contains(descriptions, "12\"")) {
                            for (Disque d : album.getDisques()) {
                                d.setTaille(Taille.taille30.getId());
                            }
                        } else if (contains(descriptions, "10\"")) {
                            for (Disque d : album.getDisques()) {
                                d.setTaille(Taille.taille25.getId());
                            }
                        } else if (contains(descriptions, "7\"")) {
                            for (Disque d : album.getDisques()) {
                                d.setTaille(Taille.taille17.getId());
                            }
                        }

                        if (contains(descriptions, "16 ⅔ RPM")) {
                            for (Disque d : album.getDisques()) {
                                d.setVitesse(Vitesse.vitesse16.getId());
                            }
                        } else if (contains(descriptions, "33 ⅓ RPM")) {
                            for (Disque d : album.getDisques()) {
                                d.setVitesse(Vitesse.vitesse33.getId());
                            }
                        } else if (contains(descriptions, "45 RPM")) {
                            for (Disque d : album.getDisques()) {
                                d.setVitesse(Vitesse.vitesse45.getId());
                            }
                        } else if (contains(descriptions, "78 RPM")) {
                            for (Disque d : album.getDisques()) {
                                d.setVitesse(Vitesse.vitesse78.getId());
                            }
                        }
                    }
                }
            }
        } 
        for (Disque d : album.getDisques()) {
            if (d.getVitesse() == null) {
                d.setVitesse(Vitesse.vitesseNA.getId());
            }
            
            if (d.getTaille() == null) {
                d.setTaille(Taille.tailleNA.getId());
            }
        }
        
        return album;
    }
    
    
    private static List<Disque> getDisques(Track[] tracks, boolean isOneSide, boolean compil) {
        List<Disque> ret = new ArrayList<>();
        
        char lastPostionCurrent = ' ';
        
        Disque currentDisc = new Disque();
        ret.add(currentDisc);
        boolean faceA = true;
        int nbr = 1;
        
        List<Track> fullList = new ArrayList<>();
        for (Track track : tracks) {
            if (track.getType_() != null) {
                if (track.getType_().equals("track")) {
                    fullList.add(track);
                } else if (track.getType_().equals("index")) {
                    if (track.getSub_tracks() != null) {
                        for (Track sub : track.getSub_tracks()) {
                            sub.setTitle(track.getTitle() + " - " + sub.getTitle());
                            fullList.add(sub);
                        }
                    }
                }
            }
        }
        
        
        
        for (Track track : fullList) {
            String position = track.getPosition();            
            if (position != null && !position.isEmpty()) {

                if (StringUtils.isNumeric(position)) {
                    // Cas 1 face 1 disque --> Je commence
                } else {
                    char lastPostion = position.charAt(0);
                    if (lastPostionCurrent == ' ') {
                        lastPostionCurrent = lastPostion; // Je commence
                    } else {
                        if (lastPostion != lastPostionCurrent) {
                            nbr = 1;
                            lastPostionCurrent = lastPostion;
                            if (isOneSide) {
                                currentDisc = new Disque();
                                ret.add(currentDisc);
                                faceA = true;
                            } else {
                                if (faceA) {
                                    faceA = false;
                                } else {
                                    faceA = true;
                                    currentDisc = new Disque();
                                    ret.add(currentDisc);
                                }
                            }
                        }
                    }
                }


                Titre titre = new Titre();
                titre.setNom(track.getTitle());
                titre.setNum(nbr++);
                try {
                    titre.setDuree(Tools.getDuree((String) track.getDuration()));
                } catch (VinylManagerException ex) {
                    VinylManagerLogger.log(ex);
                }

                if (compil) {
                    titre.setArtiste(track.getArtistsString());
                }

                if (faceA) {
                    currentDisc.getFaceA().add(titre);
                } else {
                    currentDisc.getFaceB().add(titre);
                }
            } 
        }
        
        
        return ret;
        
    }
    
    private static boolean contains(String[] arr, String val) {
        for (String s : arr) {
            if(s.equals(val)) {
                return true;
            }
        }
        return false;
    }
    
    
    public static List<Album> getDiscogsUserReleases(String username, WaitThread wt) throws VinylManagerException {
        List<Album> ret = new ArrayList<>();
        List<FolderRelease> allReleases = getReleases(username, wt);
        wt.setProgressMax(allReleases.size());
        int i = 1;
        for (FolderRelease release : allReleases) {
            wt.setProgressCurrent("Release", i++);
            Release r = DiscogsDownloader.getRelease(release.getId());
            if (r == null) {
                continue;
            }
            ret.add(getReleaseAsAlbum(r));
        }
        return ret;
    }
    
    public static List<FolderRelease> getReleases(String username, WaitThread wt) {
        FolderReleaseResponse frr = DiscogsDownloader.getFolderReleases(username, 0);
        if (frr == null || frr.getPagination() == null) {
            return new ArrayList<>();
        }
        wt.setProgressMax(frr.getPagination().getPages());
        return getReleases(username, frr, wt);
    }
    private static List<FolderRelease> getReleases(String username, FolderReleaseResponse frr, WaitThread wt) {
        wt.setProgressCurrent("Folder", frr.getPagination().getPage());
        List<FolderRelease> ret = new ArrayList<>();
        if (frr == null || frr.getPagination() == null || frr.getReleases() == null) {
            return ret;
        }
        for(FolderRelease fr : frr.getReleases()) {
            ret.add(fr);
        }
        if (frr.getPagination().getPage() < frr.getPagination().getPages()) {
            ret.addAll(getReleases(username, DiscogsDownloader.getFolderReleases(username, 0, frr.getPagination().getPage()+1), wt));
        }
        return ret;
    }
}