import logoDefault from './logo.svg';
import './App.scss';
import {Provider, connect}   from 'react-redux';
import {createStore, combineReducers, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import { BrowserRouter as Router, Route, Routes, Link} from 'react-router-dom';



function authReducer(state, { type, token }) {
  if (!state) {
      if (localStorage.authToken) {
          type = 'AUTH_LOGIN'
          token = localStorage.authToken
      } else state = {}
  }
  if (type === 'AUTH_LOGIN') {
      localStorage.setItem('authToken', token)
      let payload = jwtDecode(token)
      if (typeof payload === 'object') {
          return {
              ...state,
              token,
              payload
          }
      } else return state
  }
  if (type === 'AUTH_LOGOUT') {
      localStorage.removeItem('authToken')
      return {}
  }
  return state
}

const jwtDecode = token => {
  try {
      let arrToken = token.split('.')
      let base64Token = atob(arrToken[1])
      return JSON.parse(base64Token)
  }
  catch (e) {
      console.log('Лажа, Бро ' + e);
  }
}
const actionAuthLogin = token => ({ type: 'AUTH_LOGIN', token })
const actionAuthLogout = () => ({ type: 'AUTH_LOGOUT' })



const actionLogin = (login, password) =>
    actionPromise('login', gql(`query NameForMe1($login:String, $password:String){
            login(login:$login, password:$password)
        }`, { login, password }))


function cartReducer(state = {}, { type, good = {}, count = 1 }) {
    const { _id } = good
    const types = {
        CART_ADD() {
            count = +count  
            if (!count) {
              return state
            }            
            return {
                ...state,
                [_id]: {good, count: (count + (state[_id]?.count || 0)) < 0 ? 0 : count + (state[_id]?.count || 0)}
            }
        },
        CART_CHANGE() {
            count = +count
            if (!count) {
              return state
            } 
            return {
                ...state,
                [_id]: {good, count: count < 0 ? 0 : count}
            }
        },
        CART_REMOVE() {
            let { [_id]: remove, ...newState } = state
            return {
                ...newState
            }
        },
        CART_CLEAR() {
            return {}
        },
    }
    if (type in types) {
        return types[type]()
    }
    return state
}

const actionCartAdd = (good, count) => ({type: 'CART_ADD', good, count})
const actionCartChange = (good, count) => ({type: 'CART_CHANGE', good, count})
const actionCartRemove = (good) => ({type: 'CART_REMOVE', good})
const actionCartClear = () => ({type: 'CART_CLEAR'})



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

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))
        try {
            let data = await promise
            dispatch(actionResolved(name, data))
            return data
        }
        catch (error) {
            dispatch(actionRejected(name, error))
        }
    }
)


const actionRootCats = () => (
    actionPromise('rootCats', gql(`query {
            CategoryFind(query: "[{\\"parent\\":null}]"){
                _id name
            }
        }`))
)


const actionCatById = (_id) => (
  actionPromise('catById', gql(`query catById($q: String){
      CategoryFindOne(query: $q){
          _id name goods {
              _id name price images {
                  url
              }
          }
          subCategories {
              _id name 
          }
      }
  }`, {q: JSON.stringify([{_id}])}))
)

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

const backURL = 'http://shop-roles.asmer.fs.a-level.com.ua'
const gql = getGQL(backURL + '/graphql');


const store = createStore(combineReducers({promise: promiseReducer, auth: authReducer, cart: cartReducer}),
                                  applyMiddleware(thunk))

store.subscribe(() => console.log(store.getState()))

store.dispatch(actionRootCats())

store.dispatch(actionCatById('5dc49f4d5df9d670df48cc64'))





const Logo = ({logo}) => (
  <a href='#' className="Logo">
      <img src={logo} />
  </a>
)

const Koshik = ({cart}) => {
  let count = 0;
  console.log(cart)
  let sum = Object.entries(cart).map(([, val]) => val.count)
  count = sum.reduce((a, b) => a + b, 0)
  return (
      <Link to='/cart' className='Koshik'>{count}</Link>
  )
}

const CKoshik = connect(({cart}) => ({cart}))(Koshik)


const Header = ({logo=logoDefault}) => (
  <header>
      <CKoshik />
      <Logo logo={logo} />
  </header>
)


const defaultRootCats = [
  {_id: '5dc49f4d5df9d670df48cc64', name: 'Airconditions'},
  {_id: '5dc458985df9d670df48cc47', name: '     Smartphones'},
  {_id: '5dc4b2553f23b553bf354101', name: 'Крупная бытовая техника'},
  {_id: '5dcac1b56d09c45440d14cf8', name: 'Макароны'},
  {_id: '5dcac6cf6d09c45440d14cfd', name: 'Drinks'},
  {_id: '5dcacaeb6d09c45440d14d04', name: 'Салаты'},
  {_id: '61715b92ef4e1b3e3b67703c', name: 'Приятный бонус'},
]

const RootCategory = ({cat:{_id, name}={}}) => (
  <li>
    <Link to='/category' >{name}</Link>
    {/* <a href={`#/category/${_id}`}>{name}</a> */}
  </li>
)

const RootCategories = ({cats=defaultRootCats}) => (
  <ul className='RootCategories'>
    {cats.map(cat => <RootCategory cat={cat}/>)}
  </ul>
)

const CRootCategories = connect(state => ({cats: state.promise.rootCats?.payload || []}))(RootCategories)


const Aside = ({}) => (
  <aside>
      <CRootCategories/>
  </aside>
)

const Content = ({children}) => (
<div className='Content'>
    {children}
</div>
)

const SubCategories = ({cats}) => (
<></>
)

const GoodCard = ({good:{_id, name, price, images}={}, onCartAdd}) => (
<div className='GoodCard'>
    <h2>{name}</h2>
    {images && images[0] && images[0].url && <img src={backURL + '/' + images[0].url} />}
    <strong>{price}</strong>
    <button onClick={() => onCartAdd({_id, name, price, images})}>+</button>
</div>
)

const CGoodCard = connect(null, {onCartAdd: actionCartAdd})(GoodCard)


const Category = ({cat:{_id, name, goods, subCategories}}) => (
  <div className="Category">
    <h1>{name}</h1>
    {subCategories && <SubCategories cats={subCategories}/>}
    {(goods || []).map(good => <CGoodCard good={good}/>)}
  </div>
)

const CCategory = connect(state => ({cat: state.promise.catById?.payload || []}))(Category)



const GoodInCart = ({item: {count, good: {_id, name, price, images}}, onCartChange, onCartRemove, onCartAdd}) => (
  <div className='GoodCard'>
      <h2>{name}</h2>
      {images && images[0] && images[0].url && <img src={backURL + '/' + images[0].url} />}
      <strong>{count}</strong>
      <button onClick={() => onCartAdd({_id, name, price, images}, -1)}>-</button>
      <input onInput={(e) => onCartChange({_id, name, price, images}, e.currentTarget.value)}  value={count} type="number"/>
      <button onClick={() => onCartAdd({_id, name, price, images})}>+</button>
      <button onClick={() => onCartRemove({_id, name, price, images})}>Удалить</button>
  </div>
)

const CGoodInCart = connect(null, {onCartChange: actionCartChange, onCartRemove: actionCartRemove, onCartAdd: actionCartAdd})(GoodInCart)


const Cart = ({cartQ, onCartClear}) => (  
  <div className='Cart'>
    {cartQ.length === 0 ? <></> : <button onClick={() => onCartClear()}>Очистить корзину</button>} 
    {cartQ.map(item => <CGoodInCart item={item}/>)}
    {cartQ.length === 0 ? <></> : <button>Оформить заказ</button>} 
  </div>
)

const CCart = connect(state => ({cartQ: Object.values(state.cart) || []}), {onCartClear: actionCartClear})(Cart)


const Main = ({}) => (
  <main>
      <Aside />
      <Content>


      <Routes>

        <Route path='/cart' element={<CCart />}/>
        <Route path='/category' element={<CCategory/>}/>

      </Routes>

        
      </Content>
  </main>
)

const Footer = ({logo=logoDefault}) => (
  <footer>
      <Logo logo={logo} />
  </footer>
)





const JSONTest = ({data}) => (
  <pre>
    {JSON.stringify(data, null, 4)}
    {Math.random() > 0.5 ? <h1>qqqqqq</h1> : <h2>qq</h2>}
    {Math.random() > 0.5 && <h1>zzzz</h1>}
  </pre>
)
const ReduxJSON = connect(state => ({data: state}))(JSONTest)

const ListItem = ({item}) => (
  <li>{item}</li>
)
const List = ({data=["пиво", "чипсы", "сиги",]}) => (
  <ul>
    {/* {[  <ListItem item={data[0]}/>,
        <ListItem item={data[1]}/>,
        <ListItem item={data[2]}/>  
    ]} */}
    {data.map(item => <ListItem item={item}/>)}
  </ul>
)




function App() {
  return (
    <Provider store={store}> 
      <Router>
        <div className="App">
          <Header />       
          <Main />
          
          {/* <List /> */}
          {/* <JSONTest data={[1,2,{a:5}]} /> */}
          {/* <ReduxJSON /> */}
          <Footer />
          
        </div>
      </Router>
    </Provider>
  );
}

export default App;
