import React, { useEffect, useState, useReducer } from 'react';
import { Box, Typography, IconButton, CircularProgress } from '@material-ui/core';
import AlbumIcon from '@material-ui/icons/Album';
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 { saveAlbumChanges } from '../../../lib/saveChanges';
import { QueryLeafBy, QueryLeafOp } from '../../../lib/query/Query';
import { queryAlbums, querySongs } from '../../../lib/backend/queries';
import { songGetters } from '../../../lib/songGetters';
import { useParams } from 'react-router';

export type AlbumMetadata = serverApi.AlbumDetails;
export type AlbumMetadataChanges = serverApi.ModifyAlbumRequest;

export interface AlbumWindowState extends WindowState {
    id: number,
    metadata: AlbumMetadata | null,
    pendingChanges: AlbumMetadataChanges | null,
    songsOnAlbum: any[] | null,
    songGetters: SongGetters,
}

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

export function AlbumWindowReducer(state: AlbumWindowState, action: any) {
    switch (action.type) {
        case AlbumWindowStateActions.SetMetadata:
            return { ...state, metadata: action.value }
        case AlbumWindowStateActions.SetPendingChanges:
            return { ...state, pendingChanges: action.value }
        case AlbumWindowStateActions.SetSongs:
            return { ...state, songsOnAlbum: action.value }
        case AlbumWindowStateActions.Reload:
            return { ...state, metadata: null, pendingChanges: null, songsOnAlbum: null }
        default:
            throw new Error("Unimplemented AlbumWindow state update.")
    }
}

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

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

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

export function AlbumWindowControlled(props: {
    state: AlbumWindowState,
    dispatch: (action: any) => void,
}) {
    let { id: albumId, metadata, pendingChanges, songsOnAlbum } = props.state;
    let { dispatch } = props;

    // Effect to get the album's metadata.
    useEffect(() => {
        getAlbumMetadata(albumId)
            .then((m: AlbumMetadata) => {
                dispatch({
                    type: AlbumWindowStateActions.SetMetadata,
                    value: m
                });
            })
    }, [albumId, dispatch]);

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

        (async () => {
            const songs = await querySongs({
                query: {
                    a: QueryLeafBy.AlbumId,
                    b: albumId,
                    leafOp: QueryLeafOp.Equals,
                },
                offset: 0,
                limit: -1,
            });
            dispatch({
                type: AlbumWindowStateActions.SetSongs,
                value: songs,
            });
        })();
    }, [songsOnAlbum, albumId, dispatch]);

    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: AlbumWindowStateActions.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);
                saveAlbumChanges(props.state.id, pendingChanges || {})
                    .then(() => {
                        setApplying(false);
                        props.dispatch({
                            type: AlbumWindowStateActions.Reload
                        })
                    })
            }} />
            {applying && <CircularProgress />}
        </Box>

    return <Box width="100%" justifyContent="center" display="flex" flexWrap="wrap">
        <Box
            m={1}
            mt={4}
            width="80%"
        >
            <AlbumIcon 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 in this album in your library:</Typography>
            </Box>
            {props.state.songsOnAlbum && <SongTable
                songs={props.state.songsOnAlbum}
                songGetters={props.state.songGetters}
            />}
            {!props.state.songsOnAlbum && <CircularProgress />}
        </Box>
    </Box>
}