import React, { useEffect, useState } 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';
var _ = require('lodash');

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

export interface AlbumWindowState extends WindowState {
    albumId: 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 interface IProps {
    state: AlbumWindowState,
    dispatch: (action: any) => void,
    mainDispatch: (action: any) => void,
}

export async function getAlbumMetadata(id: number) {
    const query = {
        prop: serverApi.QueryElemProperty.albumId,
        propOperand: id,
        propOperator: serverApi.QueryFilterOp.Eq,
    };

    var q: serverApi.QueryRequest = {
        query: query,
        offsetsLimits: {
            albumOffset: 0,
            albumLimit: 1,
        },
        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();
        let album = json.albums[0];
        return album;
    })();
}

export default function AlbumWindow(props: IProps) {
    let metadata = props.state.metadata;
    let pendingChanges = props.state.pendingChanges;

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

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

        var q: serverApi.QueryRequest = {
            query: {
                prop: serverApi.QueryElemProperty.albumId,
                propOperator: serverApi.QueryFilterOp.Eq,
                propOperand: props.state.albumId,
            },
            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),
        };

        (async () => {
            const response = await fetch((process.env.REACT_APP_BACKEND || "") + serverApi.QueryEndpoint, requestOpts)
            let json: any = await response.json();
            props.dispatch({
                type: AlbumWindowStateActions.SetSongs,
                value: json.songs,
            });
        })();
    }, [props.state.songsOnAlbum]);

    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"
        >
            <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.albumId, 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}
                mainDispatch={props.mainDispatch}
            />}
            {!props.state.songsOnAlbum && <CircularProgress />}
        </Box>
    </Box>
}