import logo from './logo.svg';
import './App.css';
import React, {useCallback} from 'react'
import thunk from 'redux-thunk';
import {createStore, combineReducers, applyMiddleware} from 'redux';
import {Provider, connect} from 'react-redux';
import {useDropzone} from 'react-dropzone'

const actionPending  = name => ({type: 'PROMISE', status: 'PENDING', name})
const actionResolved = (name, payload) => ({type: 'PROMISE', status: 'RESOLVED', name, payload})
const actionRejected = (name, error) => ({type: 'PROMISE', status: 'REJECTED', name,  error})

const actionPromise = (name, promise) =>
    async dispatch => {
        dispatch(actionPending(name)) // 1. {delay1000: {status: 'PENDING'}}
        try{
            let payload = await promise
            dispatch(actionResolved(name, payload))
            return payload
        }
        catch(error){
            dispatch(actionRejected(name, error))
        }
    }

const getGQL = url =>
   (query, variables = {}) =>
      fetch(url, {
         method: 'POST',
         headers: {
            "Content-Type": "application/json",
            ...(localStorage.authToken ? { "Authorization": "Bearer " + localStorage.authToken } :
               {})
         },
         body: JSON.stringify({ query, variables })
      })
         .then(res => res.json())
         .then(data => {
            if (data.errors && !data.data)
               throw new Error(JSON.stringify(data.errors))
            return data.data[Object.keys(data.data)[0]]
         })

const backendURL = "http://player.asmer.fs.a-level.com.ua" 
const gql        = getGQL(backendURL + '/graphql')

function jwtDecode(token) {
  try {
      let decoded = token.split('.')
      decoded = decoded[1]
      decoded = atob(decoded)
      decoded = JSON.parse(decoded)
      return decoded

  } catch (e) {
      return;
  }
}


const actionLoadFile = (file) => {
  let fd = new FormData
  fd.append('photo', file)

  return (
    actionPromise('loadFile', fetch(backendURL + '/upload',{
      method: "POST",
      headers: localStorage.authToken ? {Authorization: 'Bearer ' + localStorage.authToken} : {},
      body: fd
    })
      .then(res => res.json())
    )
  )
}

const actionAboutMe = () => {
  let _id = jwtDecode(localStorage.authToken).sub.id
  return (
    actionPromise('aboutUser', gql(`
    query($userId: String!) {
      UserFindOne(query: $userId){
        login, _id, avatar {_id, url, originalFileName}
      }
    }
    `, { userId: JSON.stringify([{_id}]) }))
  )  
}

const actionSetAvatar = (file) =>
  async (dispatch, getState) => {
    await dispatch(actionLoadFile(file))
    let picId = getState().promise?.loadFile?.payload?._id
    let userId = jwtDecode(localStorage.authToken).sub.id
    await dispatch(actionPromise('setAvatar', gql(`
      mutation {
        UserUpsert(user:{_id: "${userId}", avatar: {_id: "${picId}"}}){
          _id, login, avatar{
              _id, url
          }
        }
      }
    `)))
    dispatch(actionAboutMe())
  }

function promiseReducer(state={}, {type, name, status, payload, error}){
  if (type === 'PROMISE'){
      return {
          ...state,
          [name]:{status, payload, error}
      }
  }
  return state
}

const store = createStore(
  combineReducers(
    {
      promise: promiseReducer,
    }
  ), applyMiddleware(thunk)
)
store.subscribe(() => console.log(store.getState()))

function MyDropzone({uploadAvatar, userData, onLoad}) {
  const onDrop = useCallback(acceptedFiles => {
    uploadAvatar(acceptedFiles[0])
  }, [])
  const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop})

  return (
    <div {...getRootProps()}>
      <input {...getInputProps()} />
      {
        isDragActive ?
          <p>Drop the files here ...</p> :
          <p>Drag 'n' drop some files here, or click to select files</p>
      }
    </div>
  )
}

const ConnectDropzone = connect(null, {uploadAvatar: actionSetAvatar, onLoad: actionLoadFile, userData: actionAboutMe})(MyDropzone)

function App() {
  return (
    <Provider store={store}>
      <div className="App">
        <ConnectDropzone />
      </div>
    </Provider>
  );
}

export default App;
