import React, {Fragment, useEffect, useState} from "react";
import queryString from "query-string";

import {searchArtist, searchDisc, searchSong} from "../services/search_service";
import {SearchBar} from "./SearchBar";
import {Paginate} from "./Paginate";
import {Link} from "react-router-dom";
import {Tab, TabList, TabPanel, Tabs} from "react-tabs";

import {ReactComponent as DiscSVG} from "../svg/disc.svg";

const CoverArt = (props) => {
    const [loading, setLoading] = useState(true);

    const handleLoad = () => setLoading(false)

    if (props.cover_art) {
        if (loading) {
            return (
                <Fragment>
                    <img src={props.cover_art.image} className={'coverart loading'} alt={props.alt} onLoad={handleLoad}/>
                    <DiscSVG className='coverart'/>
                </Fragment>
            )
        } else {
            return <img src={props.cover_art.image} className={'coverart'} alt={props.alt}/>
        }
    } else {
        return <DiscSVG className='coverart'/>
    }
}

const SearchPlaceholder = (props) => {
    return (
        <Fragment>
            {[...Array(10)].map((e, i) => <li key={i} className={props.className + ' pulsating'}/>)}
        </Fragment>
    )
}

const SearchSong = (props) => {
    const song = props.song;
    return (
        <li className='song'>
            <Link to={`/song/${song.id}`}>
                <div className='description'>
                    <span>{song.title}</span>
                    <span className='small'>{song.artist[0].name}</span>
                </div>
            </Link>
        </li>
    )
}

const SearchSongs = (props) => {
    const [songs, setSongs] = useState(null);
    const [paginate, setPaginate] = useState(null);
    const [page, setPage] = useState(props.page ? props.page : 1);

    useEffect(() => {
        setSongs(null);
        setPaginate(null);
        loadSongs(props.query, page)
    }, [props.query, page]);

    const makeLink = page => `/search/song?query=${props.query}&page=${page}`;

    const handlePageChange = page => {
        setSongs(null);
        setPage(page);
        props.onPageChange(page);
    }

    const loadSongs = (query, page) => {
        page = page ? page : 1;

        searchSong(query, page).then((response) => {
            setSongs(response.recordings);
            setPaginate(response.paginate);
        })
    };

    let songsComponent = <SearchPlaceholder className='song'/>;
    if (songs) {
        songsComponent = songs.map((song) => <SearchSong key={song.id} song={song}/>);
    }

    let paginateComponent;
    if (paginate) {
        const total = paginate.total;
        const currentPage = paginate.current_page;
        const pageLimit = paginate.per_page;

        paginateComponent = <Paginate totalRecords={total} pageLimit={pageLimit} currentPage={currentPage} pageNeighbours={2} onPageChanged={handlePageChange} makeLink={makeLink}/>
    }

    return (
        <Fragment>
            <ul className='entity_list'>
                {songsComponent}
            </ul>
            {paginateComponent}
        </Fragment>
    )
}

const SearchDisc = (props) => {
    const disc = props.disc;
    return (
        <li className='disc'>
            <Link to={`/disc/${disc.id}`}>
                <CoverArt cover_art={disc.cover_art} alt={`Cover del disco: ${disc.title}`}/>
                <div className='description'>
                    <span>{disc.title}</span>
                    <span className='small'>{disc.artist[0].name}</span>
                </div>
            </Link>
        </li>
    )
}

const SearchDiscs = (props) => {
    const [discs, setDiscs] = useState(null);
    const [paginate, setPaginate] = useState(null);
    const [page, setPage] = useState(null);

    useEffect(_ => {
        setDiscs(null)
        setPaginate(null)
        loadDiscs(props.query, page)
    }, [props.query, page])

    const makeLink = page => `/search/disc?query=${props.query}&page=${page}`;

    const handlePageChange = page => {
        setDiscs(null);
        setPage(page);
        props.onPageChange(page);
    }

    const loadDiscs = (query, page) => {
        page = page ? page : 1;

        searchDisc(query, page).then((response) => {
            setDiscs(response.discs);
            setPaginate(response.paginate);
        })
    };

    let discsComponent = <SearchPlaceholder className='disc'/>;
    if (discs) {
        discsComponent = discs.map((disc) => <SearchDisc key={disc.id} disc={disc}/>);
    }

    let paginateComponent;
    if (paginate) {
        const total = paginate.total;
        const currentPage = paginate.current_page;
        const pageLimit = paginate.per_page;

        paginateComponent = <Paginate totalRecords={total} pageLimit={pageLimit} currentPage={currentPage} pageNeighbours={2} onPageChanged={handlePageChange} makeLink={makeLink}/>
    }

    return (
        <Fragment>
            <ul className='entity_list'>
                {discsComponent}
            </ul>
            {paginateComponent}
        </Fragment>
    )
}

const SearchArtist = (props) => {
    const artist = props.artist;
    return (
        <li className='artist'>
            <Link to={`/artist/${artist.id}`}>
                <span className='description'>
                    <span>{artist.name}</span>
                    <span className='small'>{[artist.type, artist.country].filter(Boolean).join(' - ')}</span>
                </span>
            </Link>
        </li>
    )
}

const SearchArtists = (props) => {
    const [artists, setArtist] = useState(null);
    const [paginate, setPaginate] = useState(null);
    const [page, setPage] = useState(props.page ? props.page : 1);

    useEffect(_ => {
        setArtist(null)
        setPaginate(null)
        loadArtists(props.query, page)
    }, [props.query, page])

    const makeLink = page => `/search/artist?query=${props.query}&page=${page}`;

    const handlePageChange = page => {
        setArtist(null);
        setPage(page);
        props.onPageChange(page);
    }

    const loadArtists = (query, page) => {
        page = page ? page : 1;

        searchArtist(query, page).then((response) => {
            setArtist(response.artists);
            setPaginate(response.paginate);
        })
    };

    let artistsContent = <SearchPlaceholder className='artist'/>;
    if (artists) {
        artistsContent = artists.map((artist) => <SearchArtist key={artist.id} artist={artist}/>);
    }

    let paginateContent;
    if (paginate) {
        const total = paginate.total;
        const currentPage = paginate.current_page;
        const pageLimit = paginate.per_page;

        paginateContent = <Paginate totalRecords={total} pageLimit={pageLimit} currentPage={currentPage} pageNeighbours={2} onPageChanged={handlePageChange} makeLink={makeLink}/>
    }

    return (
        <Fragment>
            <ul className='entity_list'>
                {artistsContent}
            </ul>
            {paginateContent}
        </Fragment>
    )
}

const SearchTabs = (props) => {
    const nameToIndex = (name) => {
        if (name === 'artist') return 0
        if (name === 'disc') return 1
        if (name === 'song') return 2
        else return 0;
    }

    const indexToName = (index) => {
        if (index === 0) return 'artist'
        if (index === 1) return 'disc'
        if (index === 2) return 'song'
        else return 'artist';
    }

    const handleSelect = (index) => {
        props.onTabChanged(indexToName(index))
    }

    const handlePageChange = (who) => (index) => props.onPageChange(who, index);

    return (
        <Tabs selectedIndex={nameToIndex(props.selected)} onSelect={handleSelect}>
            <TabList className='tabs'>
                <Tab className='tab' selectedClassName='selected'>Artistas</Tab>
                <Tab className='tab' selectedClassName='selected'>Discos</Tab>
                <Tab className='tab' selectedClassName='selected'>Canciones</Tab>
            </TabList>
            <TabPanel><SearchArtists query={props.query} page={props.page} onPageChange={handlePageChange('artist')}/></TabPanel>
            <TabPanel><SearchDiscs query={props.query} page={props.page} onPageChange={handlePageChange('disc')}/></TabPanel>
            <TabPanel><SearchSongs query={props.query} page={props.page} onPageChange={handlePageChange('song')}/></TabPanel>
        </Tabs>
    )
}

export const Search = (props) => {
    const parsedParams = queryString.parse(props.location.search);
    const [who, setWho] = useState(props.match.params['who'] ? props.match.params['who'] : 'artist')
    const [query, setQuery] = useState(parsedParams.query)
    const [page, setPage] = useState(!isNaN(+parsedParams.page) ? +parsedParams.page : 1)

    const navigateTo = (who, query, page) => props.history.push(`/search/${who}?query=${query}&page=${page}`);

    const handleQueryChange = query => {
        setQuery(query);
        setPage(1);
        navigateTo(who, query, 1)
    };

    const handleTabChange = who => {
        setWho(who);
        setPage(1)
        navigateTo(who, query, 1)
    };

    const handlePageChange = (who, page) => {
        setWho(who);
        setPage(page);
        navigateTo(who, query, page);

        window.scroll({left: 0, top: 0, behavior: 'smooth'});
    };

    const content = _ => {
        if (query) {
            return <SearchTabs query={query} onTabChanged={handleTabChange} onPageChange={handlePageChange} selected={who} page={page}/>
        } else {
            return null;
        }
    }

    return (
        <Fragment>
            <h1>Búsqueda</h1>
            <SearchBar query={query} onQueryChanged={handleQueryChange} history={props.history}/>
            {content()}
        </Fragment>
    );
}
