import React, { useEffect, useState, useReducer } from 'react';
import { Box, Typography, IconButton, CircularProgress } from '@material-ui/core';
import PersonIcon from '@material-ui/icons/Person';
import * as serverApi from '../../../api';
import { WindowState } from '../Windows';
import StoreLinkIcon, { whichStore } from '../../common/StoreLinkIcon';
import EditableText from '../../common/EditableText';
import SubmitChangesButton from '../../common/SubmitChangesButton';
import SongTable, { SongGetters } from '../../tables/ResultsTable';
import { saveArtistChanges } from '../../../lib/saveChanges';
import { QueryLeafBy, QueryLeafOp } from '../../../lib/query/Query';
import { queryArtists, querySongs } from '../../../lib/backend/queries';
import { songGetters } from '../../../lib/songGetters';
import { useParams } from 'react-router';
import { handleNotLoggedIn, NotLoggedInError } from '../../../lib/backend/request';
import { useAuth } from '../../../lib/useAuth';

export type ArtistMetadata = serverApi.ArtistDetails;
export type ArtistMetadataChanges = serverApi.ModifyArtistRequest;

export interface ArtistWindowState extends WindowState {
    id: number,
    metadata: ArtistMetadata | null,
    pendingChanges: ArtistMetadataChanges | null,
    songsByArtist: any[] | null,
    songGetters: SongGetters,
}

export enum ArtistWindowStateActions {
    SetMetadata = "SetMetadata",
    SetPendingChanges = "SetPendingChanges",
    SetSongs = "SetSongs",
    Reload = "Reload",
}

export function ArtistWindowReducer(state: ArtistWindowState, action: any) {
    switch (action.type) {
        case ArtistWindowStateActions.SetMetadata:
            return { ...state, metadata: action.value }
        case ArtistWindowStateActions.SetPendingChanges:
            return { ...state, pendingChanges: action.value }
        case ArtistWindowStateActions.SetSongs:
            return { ...state, songsByArtist: action.value }
        case ArtistWindowStateActions.Reload:
            return { ...state, metadata: null, pendingChanges: null, songsByArtist: null }
        default:
            throw new Error("Unimplemented ArtistWindow state update.")
    }
}

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

export async function getArtistMetadata(id: number) {
    return (await queryArtists({
        query: {
            a: QueryLeafBy.ArtistId,
            b: id,
            leafOp: QueryLeafOp.Equals,
        },
        offset: 0,
        limit: 1,
    }))[0];
}

export default function ArtistWindow(props: {}) {
    const { id } = useParams();
    const [state, dispatch] = useReducer(ArtistWindowReducer, {
        id: id,
        metadata: null,
        pendingChanges: null,
        songGetters: songGetters,
        songsByArtist: null,
    });

    return <ArtistWindowControlled state={state} dispatch={dispatch} />
}

export function ArtistWindowControlled(props: {
    state: ArtistWindowState,
    dispatch: (action: any) => void,
}) {
    let { metadata, id: artistId, pendingChanges, songsByArtist } = props.state;
    let { dispatch } = props;
    let auth = useAuth();

    // Effect to get the artist's metadata.
    useEffect(() => {
        getArtistMetadata(artistId)
            .then((m: ArtistMetadata) => {
                dispatch({
                    type: ArtistWindowStateActions.SetMetadata,
                    value: m
                });
            })
            .catch((e: NotLoggedInError) => { handleNotLoggedIn(auth, e) })
    }, [artistId, dispatch]);

    // Effect to get the artist's songs.
    useEffect(() => {
        if (songsByArtist) { return; }

        (async () => {
            const songs = await querySongs({
                query: {
                    a: QueryLeafBy.ArtistId,
                    b: artistId,
                    leafOp: QueryLeafOp.Equals,
                },
                offset: 0,
                limit: -1,
            })
            .catch((e: NotLoggedInError) => { handleNotLoggedIn(auth, e) });
            dispatch({
                type: ArtistWindowStateActions.SetSongs,
                value: songs,
            });
        })();
    }, [songsByArtist, dispatch, artistId]);

    const [editingName, setEditingName] = useState<string | null>(null);
    const name = <Typography variant="h4"><EditableText
        defaultValue={metadata?.name || "(Unknown name)"}
        changedValue={pendingChanges?.name || null}
        editingValue={editingName}
        editingLabel="Name"
        onChangeEditingValue={(v: string | null) => setEditingName(v)}
        onChangeChangedValue={(v: string | null) => {
            let newVal: any = { ...pendingChanges };
            if (v) { newVal.name = v }
            else { delete newVal.name }
            props.dispatch({
                type: ArtistWindowStateActions.SetPendingChanges,
                value: newVal,
            })
        }}
    /></Typography>

    const storeLinks = metadata?.storeLinks && metadata?.storeLinks.map((link: string) => {
        const store = whichStore(link);
        return store && <a
            href={link} target="_blank" rel="noopener noreferrer"
        >
            <IconButton><StoreLinkIcon
                whichStore={store}
                style={{ height: '40px', width: '40px' }}
            />
            </IconButton>
        </a>
    });

    const [applying, setApplying] = useState(false);
    const maybeSubmitButton = pendingChanges && Object.keys(pendingChanges).length > 0 &&
        <Box>
            <SubmitChangesButton onClick={() => {
                setApplying(true);
                saveArtistChanges(props.state.id, pendingChanges || {})
                    .then(() => {
                        setApplying(false);
                        props.dispatch({
                            type: ArtistWindowStateActions.Reload
                        })
                    })
                    .catch((e: NotLoggedInError) => { handleNotLoggedIn(auth, e) })
            }} />
            {applying && <CircularProgress />}
        </Box>

    return <Box width="100%" justifyContent="center" display="flex" flexWrap="wrap">
        <Box
            m={1}
            mt={4}
            width="80%"
        >
            <PersonIcon style={{ fontSize: 80 }} />
        </Box>
        <Box
            m={1}
            width="80%"
        >
            {metadata && <Box>
                <Box m={2}>
                    {name}
                </Box>
                <Box m={1}>
                    <Box display="flex" alignItems="center" m={0.5}>
                        {storeLinks}
                    </Box>
                </Box>
            </Box>}
        </Box>
        <Box
            m={1}
            width="80%"
        >
            {maybeSubmitButton}
        </Box>
        <Box
            m={1}
            width="80%"
        >
            <Box display="flex" flexDirection="column" alignItems="left">
                <Typography>Songs by this artist in your library:</Typography>
            </Box>
            {props.state.songsByArtist && <SongTable
                songs={props.state.songsByArtist}
                songGetters={props.state.songGetters}
            />}
            {!props.state.songsByArtist && <CircularProgress />}
        </Box>
    </Box>
}