import React, { useEffect } from 'react';
import { createMuiTheme, Box, LinearProgress } from '@material-ui/core';
import { QueryElem, toApiQuery } from '../../lib/query/Query';
import QueryBuilder from '../querybuilder/QueryBuilder';
import * as serverApi from '../../api';
import { SongTable } from '../tables/ResultsTable';
import stringifyList from '../../lib/stringifyList';
import { getArtists, getSongTitles, getAlbums, getTags } from '../../lib/query/Getters';
import { grey } from '@material-ui/core/colors';
import { WindowState } from './Windows';
var _ = require('lodash');

const darkTheme = createMuiTheme({
    palette: {
        type: 'dark',
        primary: {
            main: grey[100],
        }
    },
});

export interface ResultsForQuery {
    for: QueryElem,
    results: any[],
};

export interface QueryWindowState extends WindowState {
    editingQuery: boolean,
    query: QueryElem | null,
    resultsForQuery: ResultsForQuery | null,
}

export enum QueryWindowStateActions {
    SetQuery = "setQuery",
    SetEditingQuery = "setEditingQuery",
    SetResultsForQuery = "setResultsForQuery",
}

export function QueryWindowReducer(state: QueryWindowState, action: any) {
    switch (action.type) {
        case QueryWindowStateActions.SetQuery:
            return { ...state, query: action.value }
        case QueryWindowStateActions.SetEditingQuery:
            return { ...state, editingQuery: action.value }
        case QueryWindowStateActions.SetResultsForQuery:
            return { ...state, resultsForQuery: action.value }
        default:
            throw new Error("Unimplemented QueryWindow state update.")
    }
}

export interface IProps {
    state: QueryWindowState,
    dispatch: (action: any) => void,
    mainDispatch: (action: any) => void,
}

export default function QueryWindow(props: IProps) {
    let query = props.state.query;
    let editing = props.state.editingQuery;
    let resultsFor = props.state.resultsForQuery;
    let setQuery = (q: QueryElem | null) => {
        props.dispatch({ type: QueryWindowStateActions.SetQuery, value: q });
    }
    let setEditingQuery = (e: boolean) => {
        props.dispatch({ type: QueryWindowStateActions.SetEditingQuery, value: e });
    }
    let setResultsForQuery = (r: ResultsForQuery | null) => {
        props.dispatch({ type: QueryWindowStateActions.SetResultsForQuery, value: r });
    }

    const loading = query && (!resultsFor || !_.isEqual(resultsFor.for, query));
    const showResults = (query && resultsFor && query == resultsFor.for) ? resultsFor.results : [];

    const songGetters = {
        getTitle: (song: any) => song.title,
        getArtistNames: (song: any) => song.artists.map((a: any) => a.name),
        getArtistIds: (song: any) => song.artists.map((a: any) => a.artistId),
        getAlbumNames: (song: any) => song.albums.map((a: any) => a.name),
        getTagNames: (song: any) => {
            // Recursively resolve the name.
            const resolveTag = (tag: any) => {
                var r = [tag.name];
                if (tag.parent) { r.unshift(resolveTag(tag.parent)); }
                return r;
            }

            return song.tags.map((tag: any) => resolveTag(tag));
        }
    }

    const doQuery = async (_query: QueryElem) => {
        var q: serverApi.QueryRequest = {
            query: toApiQuery(_query),
            offsetsLimits: {
                songOffset: 0,
                songLimit: 100,
            },
            ordering: {
                orderBy: {
                    type: serverApi.OrderByType.Name,
                },
                ascending: true,
            },
        };

        const requestOpts = {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(q),
        };

        return (async () => {
            const response = await fetch((process.env.REACT_APP_BACKEND || "") + serverApi.QueryEndpoint, requestOpts)
            let json: any = await response.json();
            if (_.isEqual(query, _query)) {
                setResultsForQuery({
                    for: _query,
                    results: json.songs,
                })
            }
        })();
    }

    useEffect(() => {
        if (query) {
            doQuery(query);
        } else {
            setResultsForQuery(null);
        }
    }, [query]);

    return <Box width="100%" justifyContent="center" display="flex" flexWrap="wrap">
        <Box
            m={1}
            width="80%"
        >
            <QueryBuilder
                query={query}
                onChangeQuery={setQuery}
                editing={editing}
                onChangeEditing={setEditingQuery}
                requestFunctions={{
                    getArtists: getArtists,
                    getSongTitles: getSongTitles,
                    getAlbums: getAlbums,
                    getTags: getTags,
                }}
            />
        </Box>
        <Box
            m={1}
            width="80%"
        >
            <SongTable
                songs={showResults}
                songGetters={songGetters}
                mainDispatch={props.mainDispatch}
            />
            {loading && <LinearProgress />}
        </Box>
    </Box>
}