import React, {Fragment} 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";

class CoverArt extends React.Component  {
    constructor(props) {
       super(props);
       this.state = {
           loading: true
       }
    }

    handleLoad = () => {
        this.setState({loading: false})
    };

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


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

class SearchSong extends React.Component {
    render() {
        const song = this.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>
        )
    }
}

class SearchSongs extends React.Component {
    constructor(props) {
        super(props);
        this.state = {songs: null, paginate: null, page: this.props.page ? this.props.page : 1}
    }

    componentDidMount = _ => this.loadSongs(this.props.query, this.state.page);

    componentDidUpdate = (prevProps, prevState) => {
        if (prevProps.query !== this.props.query || prevState.page !== this.state.page) {
            this.loadSongs(this.props.query, this.state.page)

            if (prevState.page !== this.state.page) {
                this.setState({songs: null})
            } else {
                this.setState({songs: null, paginate: null})
            }
        }
    };

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

    handlePageChange = page => {
        this.setState({songs: null, page: page})
        this.props.onPageChange(page);
    }

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

        searchSong(query, page).then((response) => {
            this.setState({
                songs: response.recordings,
                paginate: response.paginate
            })
        })
    };

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

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

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

        return (
            <Fragment>
                <ul className='entity_list'>
                    {songs}
                </ul>
                {paginate}
            </Fragment>
        )
    };
}

class SearchDisc extends React.Component {
    getReleaseYear = (release) => {
        const releaseDate = new Date(release);
        return (
            <span className='release-date'>{releaseDate.getFullYear()}</span>
        )
    }

    render() {
        const disc = this.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} {disc.date && this.getReleaseYear(disc.date)}</span>
                        <span className='small'>{disc.artist[0].name}</span>
                    </div>
                </Link>
            </li>
        )
    }
}

class SearchDiscs extends React.Component {
    constructor(props) {
        super(props);
        this.state = {discs: null, paginate: null, page: this.props.page ? this.props.page : 1}
    }

    componentDidMount = _ => this.loadDiscs(this.props.query, this.state.page);

    componentDidUpdate = (prevProps, prevState) => {
        if (prevProps.query !== this.props.query || prevState.page !== this.state.page) {
            this.loadDiscs(this.props.query, this.state.page)

            if (prevState.page !== this.state.page) {
                this.setState({discs: null})
            } else {
                this.setState({discs: null, paginate: null})
            }
        }
    };

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

    handlePageChange = page => {
        this.setState({discs: null, page: page})
        this.props.onPageChange(page);
    }

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

        searchDisc(query, page).then((response) => {
            this.setState({
                discs: response.releases,
                paginate: response.paginate
            })
        })
    };

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

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

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

        return (
            <Fragment>
                <ul className='entity_list'>
                    {discs}
                </ul>
                {paginate}
            </Fragment>
        )
    };
}

class SearchArtist extends React.Component {
    render() {
        const artist = this.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>
        )
    }
}

class SearchArtists extends React.Component {
    constructor(props) {
        super(props);
        this.state = {artists: null, paginate: null, page: this.props.page ? this.props.page : 1}
    }

    componentDidMount = _ => this.loadArtists(this.props.query, this.state.page);

    componentDidUpdate = (prevProps, prevState) => {
        if (prevProps.query !== this.props.query || prevState.page !== this.state.page) {
            this.loadArtists(this.props.query, this.state.page)

            if (prevState.page !== this.state.page) {
                this.setState({artists: null})
            } else {
                this.setState({artists: null, paginate: null})
            }
        }
    };

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

    handlePageChange = page => {
        this.setState({artists: null, page: page})
        this.props.onPageChange(page);
    }

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

        searchArtist(query, page).then((response) => {
            this.setState({
                artists: response.artists,
                paginate: response.paginate
            })
        })
    };

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

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

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

        return (
            <Fragment>
                <ul className='entity_list'>
                    {artists}
                </ul>
                {paginate}
            </Fragment>
        )
    };
}

class SearchTabs extends React.Component {
    constructor(props) {
        super(props);
        this.handleSelect = this.handleSelect.bind(this);
    }

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

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

    handleSelect(index) {
        if (this.props.onTabChanged) this.props.onTabChanged(this.indexToName(index))
    }

    handlePageChange = (who) => (index) => {
        this.props.onPageChange(who, index);
    }

    render() {
        return (
            <Tabs selectedIndex={this.nameToIndex(this.props.selected)} onSelect={this.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={this.props.query} page={this.props.page} onPageChange={this.handlePageChange('artist')}/></TabPanel>
                <TabPanel><SearchDiscs query={this.props.query} page={this.props.page} onPageChange={this.handlePageChange('disc')}/></TabPanel>
                <TabPanel><SearchSongs query={this.props.query} page={this.props.page} onPageChange={this.handlePageChange('song')}/></TabPanel>
            </Tabs>
        )
    }
}

export class Search extends React.Component {
    constructor(props) {
        super(props);
        const parsed = queryString.parse(this.props.location.search);
        this.state = {
            who: this.props.match.params['who'] ? this.props.match.params['who'] : 'artist',
            query: parsed.query,
            page: !isNaN(+parsed.page) ? +parsed.page : 1,
        };

        console.log(this.state);
    }

    navigateToState = () => {
        const link = `/search/${this.state.who}?query=${this.state.query}&page=${this.state.page}`;
        this.props.history.push(link);
    };

    handleQueryChange = query => {
        this.setState({query: query, page: 1}, this.navigateToState);
    };

    handleTabChange = name => {
        this.setState({who: name, page: 1}, this.navigateToState);
    };

    handlePageChange = (who, page) => {
        this.setState({who: who, page: page}, this.navigateToState);
        window.scroll({left: 0, top: 0, behavior: 'smooth'});
    };

    render = () => (
        <Fragment>
            <h1>Búsqueda</h1>
            <SearchBar query={this.state.query} onQueryChanged={this.handleQueryChange} history={this.props.history}/>
            <SearchTabs query={this.state.query} onTabChanged={this.handleTabChange} onPageChange={this.handlePageChange} selected={this.state.who} page={this.state.page}/>
        </Fragment>
    );
}
