import React, { useEffect, useState } from 'react';
import { AppBar, Box, Button, Dialog, DialogActions, Divider, FormControl, FormControlLabel, IconButton, Link, List, ListItem, ListItemIcon, ListItemText, MenuItem, Radio, RadioGroup, Select, Tab, Tabs, TextField, Typography } from "@material-ui/core";
import { SongMetadata } from "./SongWindow";
import StoreLinkIcon, { whichStore } from '../../common/StoreLinkIcon';
import CheckIcon from '@material-ui/icons/Check';
import SearchIcon from '@material-ui/icons/Search';
import CancelIcon from '@material-ui/icons/Cancel';
import OpenInNewIcon from '@material-ui/icons/OpenInNew';
import DeleteIcon from '@material-ui/icons/Delete';
import { $enum } from "ts-enum-util";
import { useIntegrations, IntegrationsState, IntegrationState } from '../../../lib/integration/useIntegrations';
import { IntegrationFeature, IntegrationSong } from '../../../lib/integration/Integration';
import { TabPanel } from '@material-ui/lab';
import { v1 } from 'uuid';
import { ExternalStore } from '../../../api';
let _ = require('lodash')

export function ProvideLinksWidget(props: {
    providers: IntegrationState[],
    metadata: SongMetadata,
    store: ExternalStore,
    onChange: (link: string | undefined) => void,
}) {
    let defaultQuery = `${props.metadata.title}${props.metadata.artists && ` ${props.metadata.artists[0].name}`}${props.metadata.albums && ` ${props.metadata.albums[0].name}`}`;

    let [selectedProviderIdx, setSelectedProviderIdx] = useState<number | undefined>(
        props.providers.length > 0 ? 0 : undefined
    );
    let [query, setQuery] = useState<string>(defaultQuery)
    let [results, setResults] = useState<IntegrationSong[] | undefined>(undefined);

    let selectedProvider: IntegrationState | undefined = selectedProviderIdx !== undefined ?
        props.providers[selectedProviderIdx] : undefined;

    let currentLink = props.metadata.storeLinks ? props.metadata.storeLinks.find(
        (l: string) => whichStore(l) === props.store
    ) : undefined;

    // Ensure results are cleared when input state changes.
    useEffect(() => {
        setResults(undefined);
        setQuery(defaultQuery);
    }, [props.store, props.providers, props.metadata])

    return <Box display="flex" flexDirection="column" alignItems="left">
        <Box display="flex" alignItems="center">
            <Typography>Search using:</Typography>
            <Box ml={2} />
            <Select
                value={selectedProviderIdx}
                onChange={(e: any) => setSelectedProviderIdx(e.target.value)}
            >
                {props.providers.map((p: IntegrationState, idx: number) => {
                    return <MenuItem value={idx}>{p.properties.name}</MenuItem>
                })}
            </Select>
        </Box>
        <TextField
            value={query}
            onChange={(e: any) => setQuery(e.target.value)}
            label="Query"
            fullWidth
        />
        <IconButton
            onClick={() => {
                selectedProvider?.integration.searchSong(query, 10)
                    .then((songs: IntegrationSong[]) => setResults(songs))
            }}
        ><SearchIcon /></IconButton>
        {results && results.length > 0 && <Typography>Suggestions:</Typography>}
        <FormControl>
            <RadioGroup value={currentLink} onChange={(e: any) => props.onChange(e.target.value)}>
                {results && results.map((result: IntegrationSong, idx: number) => {
                    let pretty = `"${result.title}"
                    ${result.artist && ` by ${result.artist.name}`}
                    ${result.album && ` (${result.album.name})`}`;
                    return <FormControlLabel
                        value={result.url || idx}
                        control={<Radio checked={(result.url || idx) === currentLink} />}
                        label={<Box display="flex" alignItems="center">
                            {pretty}
                            <a href={result.url || ""} target="_blank">
                                <IconButton><OpenInNewIcon /></IconButton>
                            </a>
                        </Box>}
                    />
                })}
                {results && results.length === 0 && <Typography>No results were found. Try adjusting the query manually.</Typography>}
            </RadioGroup>
        </FormControl>
    </Box >
}

export function ExternalLinksEditor(props: {
    metadata: SongMetadata,
    original: SongMetadata,
    onChange: (v: SongMetadata) => void,
}) {
    let [selectedIdx, setSelectedIdx] = useState<number>(0);
    let integrations = useIntegrations();

    let getLinksSet = (metadata: SongMetadata) => {
        return $enum(ExternalStore).getValues().reduce((prev: any, store: string) => {
            var maybeLink: string | null = null;
            metadata.storeLinks && metadata.storeLinks.forEach((link: string) => {
                if (whichStore(link) === store) {
                    maybeLink = link;
                }
            })
            return {
                ...prev,
                [store]: maybeLink,
            }
        }, {});
    }

    let linksSet: Record<string, string | null> = getLinksSet(props.metadata);
    let originalLinksSet: Record<string, string | null> = getLinksSet(props.original);

    let store = $enum(ExternalStore).getValues()[selectedIdx];
    let providers: IntegrationState[] = Array.isArray(integrations.state) ?
        integrations.state.filter(
            (iState: IntegrationState) => (
                iState.integration.getFeatures().includes(IntegrationFeature.SearchSong) &&
                iState.integration.providesStoreLink() === store
            )
        ) : [];

    return <Box display="flex" width="100%">
        <Box width="30%">
            <List>

                {$enum(ExternalStore).getValues().map((store: string, idx: number) => {
                    let maybeLink = linksSet[store];
                    let color: string | undefined =
                        (linksSet[store] && !originalLinksSet[store]) ? "lightgreen" :
                            (!linksSet[store] && originalLinksSet[store]) ? "red" :
                                (linksSet[store] && originalLinksSet[store] && linksSet[store] !== originalLinksSet[store]) ? "orange" :
                                    undefined;

                    return <ListItem
                        selected={selectedIdx === idx}
                        onClick={(e: any) => setSelectedIdx(idx)}
                        button
                    >
                        <ListItemIcon>{linksSet[store] !== null ? <CheckIcon style={{ color: color }} /> : <CancelIcon style={{ color: color }} />}</ListItemIcon>
                        <ListItemIcon><StoreLinkIcon whichStore={store} /></ListItemIcon>
                        <ListItemText  style={{ color: color }} primary={store} />
                        {maybeLink && <a href={maybeLink} target="_blank">
                            <ListItemIcon><IconButton><OpenInNewIcon style={{ color: color }} /></IconButton></ListItemIcon>
                        </a>}
                        {maybeLink && <ListItemIcon><IconButton
                            onClick={() => {
                                let newLinks = props.metadata.storeLinks?.filter(
                                    (l: string) => whichStore(l) !== store
                                )
                                props.onChange({
                                    ...props.metadata,
                                    storeLinks: newLinks,
                                });
                            }}
                        ><DeleteIcon style={{ color: color }} />
                        </IconButton></ListItemIcon>}
                    </ListItem>
                })}
            </List>
        </Box>
        <Box ml={2} width="60%">
            {providers.length === 0 ?
                <Typography>None of your configured integrations provides URL links for {store}.</Typography> :
                <ProvideLinksWidget
                    providers={providers}
                    metadata={props.metadata}
                    store={store}
                    onChange={(link: string | undefined) => {
                        let removed = props.metadata.storeLinks?.filter(
                            (link: string) => whichStore(link) !== store
                        ) || [];
                        let newValue = link ? [...removed, link] : removed;
                        if (!_.isEqual(new Set(newValue), new Set(props.metadata.storeLinks || []))) {
                            props.onChange({
                                ...props.metadata,
                                storeLinks: newValue,
                            })
                        }
                    }}
                />
            }
        </Box>
    </Box >
}

export default function EditSongDialog(props: {
    open: boolean,
    onClose: () => void,
    onSubmit: (v: SongMetadata) => void,
    id: number,
    metadata: SongMetadata,
}) {
    enum EditSongTabs {
        Details = 0,
        ExternalLinks,
    }

    let [editingMetadata, setEditingMetadata] = useState<SongMetadata>(props.metadata);

    return <Dialog
        maxWidth="lg"
        fullWidth
        open={props.open}
        onClose={props.onClose}
        disableBackdropClick={true}>
        <Typography variant="h5">Properties</Typography>
        <Typography>Under construction</Typography>
        <Divider />
        <Typography variant="h5">External Links</Typography>
        <ExternalLinksEditor
            metadata={editingMetadata}
            original={props.metadata}
            onChange={(v: SongMetadata) => setEditingMetadata(v)}
        />
        <Divider />
        {!_.isEqual(editingMetadata, props.metadata) && <DialogActions>
            <Button variant="contained" color="secondary"
                onClick={() => {
                    props.onSubmit(editingMetadata);
                    props.onClose();
                }}>Save all changes</Button>
            <Button variant="outlined"
                onClick={() => setEditingMetadata(props.metadata)}>Discard changes</Button>
        </DialogActions>}
    </Dialog>

}