import React, { useState, useEffect } from 'react';

import { Box, Button } from '@material-ui/core';

import * as serverApi from './api';
import SongTable, { Entry as SongEntry } from './components/SongTable';
import ArtistTable, { Entry as ArtistEntry } from './components/ArtistTable';
import EditSongDialog, { SongProperties } from './components/EditSongDialog';
import EditArtistDialog, { ArtistProperties } from './components/EditArtistDialog';

function App() {
  const [songs, setSongs] = useState<SongEntry[]>([]);
  const [artists, setArtists] = useState<ArtistEntry[]>([]);
  const [editSongDialogOpen, setEditSongDialogOpen] = useState<boolean>(false);
  const [songDialogProperties, setSongDialogProperties] = useState<SongProperties>({
    title: "",
    artistId: -1,
  });
  const [editArtistDialogOpen, setEditArtistDialogOpen] = useState<boolean>(false);
  const [artistDialogProperties, setArtistDialogProperties] = useState<ArtistProperties>({
    name: ""
  });

  const updateSongs = () => {
    return fetch(serverApi.ListSongsEndpoint)
      .then((response: any) => response.json())
      .then((result: serverApi.ListSongsResponse) => {
        setSongs(result.map((item: serverApi.ListSongsResponseItem) => {
          return {
            title: item.title,
            artistName: item.artistName
          };
        }));
      });
  }

  const fetchArtists = () => {
    return fetch(serverApi.ListArtistsEndpoint)
    .then((response: any) => response.json())
    .then((result: serverApi.ListArtistsResponse) => {
      return result.map((item: serverApi.ListArtistsResponseItem) => {
        return {
          name: item.name,
          id: item.id,
        };
      });
    });
  }

  const updateArtists = () => {
    return fetchArtists()
    .then((artists: any[]) => {
        setArtists(artists);
    });
  }

  const createSong = (p:SongProperties) => {
    if(!p.artistId) {
      throw "Undefined artist ID for song to be created.";
    }
    const request:serverApi.CreateSongRequest = {
      title: p.title,
      artistId: p.artistId,
    }
    const requestOpts = {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify(request)
    };
    return fetch(serverApi.CreateSongEndpoint, requestOpts)
  }

  const createArtist = (p:ArtistProperties) => {
    const request:serverApi.CreateArtistRequest = {
      name: p.name,
    }
    const requestOpts = {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify(request)
    };
    return fetch(serverApi.CreateArtistEndpoint, requestOpts)
  }

  const openCreateSongDialog = () => {
    setSongDialogProperties({
      title: "",
      artistId: -1,
    });
    setEditSongDialogOpen(true);
  }

  const onSubmitCreateSongDialog = () => {
    createSong(songDialogProperties)
    .then(updateSongs)
    .then(() => { setEditSongDialogOpen(false); })
  }

  const openCreateArtistDialog = () => {
    setArtistDialogProperties({
      name: "",
    });
    setEditArtistDialogOpen(true);
  }

  const onSubmitCreateArtistDialog = () => {
    createArtist(artistDialogProperties)
    .then(updateArtists)
    .then(() => { setEditArtistDialogOpen(false); })
  }

  useEffect(() => { updateSongs(); }, []);
  useEffect(() => { updateArtists(); }, []);

  return (
    <div style={{ maxWidth: '100%' }}>
      <Button variant="contained" onClick={openCreateSongDialog}>Create Song</Button>
      <Button variant="contained" onClick={openCreateArtistDialog}>Create Artist</Button>
      <Box>
        <SongTable
          songs={songs}
        />
        <ArtistTable
          artists={artists}
        /> 
      </Box>
      <EditSongDialog
        dialogOpen={editSongDialogOpen}
        onClose={() => { setEditSongDialogOpen(false); }}
        onChangeSongProperties={(props:SongProperties) => setSongDialogProperties(props)}
        songProperties={songDialogProperties}
        onSubmit={onSubmitCreateSongDialog}
        artists={artists}
      />
      <EditArtistDialog
        dialogOpen={editArtistDialogOpen}
        onClose={() => { setEditArtistDialogOpen(false); }}
        onChangeArtistProperties={(props:ArtistProperties) => setArtistDialogProperties(props)}
        artistProperties={artistDialogProperties}
        onSubmit={onSubmitCreateArtistDialog}
      />
    </div>
  );
}

export default App;