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 {useEffect, useState, useRef} from "react";
import React from 'react';

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


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 actionAuthLogin = token => ({ type: 'AUTH_LOGIN', token })
const actionAuthLogout = () => ({ type: 'AUTH_LOGOUT' })
const actionFullLogin = (login,password) =>
	async function i(dispatch){
		let token = await dispatch(actionLogin(login,password));
		console.log(token);
		if(token){
			dispatch(actionAuthLogin(token));
		}
	}

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)
                }
            }
        },
        CART_CHANGE() {
            count = +count
            if (!count) return state
            return {
                ...state,
                [_id]: {
                    good,
                    count: 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=1) => ({type: "CART_ADD", good, count});


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 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 actionRootCats = () =>
    actionPromise('rootCats', gql(`query {
            CategoryFind(query: "[{\\"parent\\":null}]"){
                _id name
            }
        }`))


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



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'))

store.dispatch(actionFullLogin('vladBraun4','123'))

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



const KoshikGood = ({obj: {good: {_id, name, price, images}={}, count=1},  onCartChange, onCartRemove}) => {
	console.log(name); 
	console.log(count);
	let [val, setVal] = useState(count)
	return(
		<div className='GoodCard2'>
			<p>{name}</p>
			{images && images[0] && images[0].url && <img src={backURL+'/'+images[0].url} />}
			<p><input type='number' value={val} onChange={e=>setVal(e.target.value)}/></p>	
			<p><strong>{price}</strong></p>
		</div>
	)
}


const KoshikGoods = ({goods}) =>{
	console.log(goods);
	return(
		<div className='GoodCard'>
			<h1>Корзина</h1>
			{Object.entries(goods).map(good2 =>{
				console.log(good2);
				return(
					<KoshikGood obj={good2[1]}/>
				)
			})}
		</div>
	)
}	

const CKoshikGoods = connect(state => ({goods: state.cart}))(KoshikGoods)




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

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

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

const defaultRootCats =  [
            {
                "_id": "5dc49f4d5df9d670df48cc64",
                "name": "Airconditions"
            },
            {
                "_id": "5dc458985df9d670df48cc47",
                "name": "     Smartphones"
            },
            {
                "_id": "5dc4b2553f23b553bf354101",
                "name": "Крупная бытовая техника"
            },
            {
                "_id": "5dcac1b56d09c45440d14cf8",
                "name": "Макароны"
            }
		]

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

const RootCategories = ({cats=defaultRootCats}) =>
    <ul>
    	{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 defaultCat = {
    "subCategories": null,
    "_id": "5dc458985df9d670df48cc47",
    "name": "     Smartphones",
    "goods": [
        {
            "_id": "5dc4a3e15df9d670df48cc6b",
            "name": "Apple iPhone 11 Pro Max 64GB Gold",
            "price": 1500,
            "images": [
                {
                    "url": "images/b599634ebfecf2a19d900e22434bedbd"
                }
            ]
        },
        {
            "_id": "5dc4a4365df9d670df48cc6c",
            "name": "Apple iPhone XS Max 256GB Gold",
            "price": 1300,
            "images": [
                {
                    "url": "images/63c4a052377862494e33746b375903f6"
                }
            ]
        },
        {
            "_id": "61b1056cc750c12ba6ba4522",
            "name": "iPhone ",
            "price": 1000,
            "images": [
                {
                    "url": "images/cc23c15a3ae1ac60582785ebf9b3d207"
                }
            ]
        },
        {
            "_id": "61b105f9c750c12ba6ba4524",
            "name": "iPhone ",
            "price": 1200,
            "images": [
                {
                    "url": "images/50842a3af34bfa28be037aa644910d07"
                }
            ]
        },
        {
            "_id": "61b1069ac750c12ba6ba4526",
            "name": "iPhone ",
            "price": 1000,
            "images": [
                {
                    "url": "images/d12b07d983dac81ccad404582a54d8be"
                }
            ]
        },
        {
            "_id": "61b23f94c750c12ba6ba472a",
            "name": "name1",
            "price": 1214,
            "images": [
                {
                    "url": null
                }
            ]
        },
        {
            "_id": "61b23fbac750c12ba6ba472c",
            "name": "smart",
            "price": 1222,
            "images": [
                {
                    "url": "images/871f4e6edbf86c35f70b72dcdebcd8b2"
                }
            ]
        }
    ]
}

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,price,subCategories}=defaultCat}) =>
	<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 CCart = connect()

const Main = ()=>
    <main>
        <Aside />
        <Content>
            <CCategory />
        </Content>
    </main>

const JSONTest = ({data}) =>
	<pre>
		{JSON.stringify(data,null,4)}
	</pre>

const ReduxJSON = connect(state => ({data:state.promise}))(JSONTest)

const ListItem = ({item}) => 
	<li>{item}</li> 

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

const _ = React.createElement.bind(React);

const List2 = ({data=["пиво","чипсы","сиги"]}) =>
	_('h1',null,
		data.map(item=> _(ListItem,{item}))
	)

const Input = () =>{
	const [text, setText] = useState("text");
	return(
		<>
			<h1>{text}</h1>
			<h1>{text.toLowerCase()}</h1>
			<h1>{text.length}</h1>
			<input value={text} onChange={e=>setText(e.target.value)}/>
		</>
		
	)
}

const RGBInput = () =>{
	const [red, setRed] = useState(0)
	const [green, setGreen] = useState(0)
	const [blue, setBlue] = useState(0)
	const color = `rgba(${red},${green},${blue})`
	const bounds = x => x<0 ? 0 : ( x>255 ? 255 : x)
	useEffect(()=>{
		console.log('component didMount')
		return ()=>{
			console.log('component willUnMount')
		}
	},[red])
	return(
		<div style={{backgroundColor:color}}>
			<input type='number' min='0' max='255' value={red} onChange={e=>setRed(bounds(+e.target.value))} />
			<input type='number' min='0' max='255' value={green} onChange={e=>setGreen(bounds(+e.target.value))} />
			<input type='number' min='0' max='255' value={blue} onChange={e=>setBlue(bounds(+e.target.value))} />
		</div>
	)
}

const Timer = ({ms=1000, onDelete}) => {
	const [count, setCount] = useState(0);
	const ref = useRef(0)
	useEffect(() => {
		console.log('+EFFECT');
		const interval = setInterval(()=>{
			setCount(count => count+1)
			//console.log(count)
		},ms)
		return () =>{
			console.log('-EFFECT')
			clearInterval(interval)
		} 
	},[ms])
	//console.log(ref.current++)
	return(
		<>
			<h3>{count}</h3>
			<button onClick={onDelete}>x</button>
		</>
	)
}

const Timers = () =>{
	const [timers, setTimers] = useState([])
	const [ms, setMS] = useState(1000)
	console.log(timers)
	return(
		<>
			<button onClick={()=>setMS(ms+100)}>+</button>{ms}
			<button onClick={()=>setMS(ms-100)}>-</button>
			<button onClick={()=>setTimers([Math.random(), ...timers])}>+</button>
			{timers.map(i=> <Timer key={i} ms={ms}
					onDelete={()=>setTimers(timers.filter(t=>t!==i))} />)}
		</>
	)
}

const LoginForm = ({onLogin}) =>{
	const [login, setLogin] = useState(''); //braunvlad4
	const [pass, setPass] = useState('');   //123
	return( 
		<div className='LoginForm'>
			<input value={login} style={{backgroundColor: login.length>0 ? 'green' : 'red'}} 
						placeholder='your login' onChange={e=>setLogin(e.target.value)} />
			<input value={pass} style={{backgroundColor: pass.length>0 ? 'green' : 'red'}} 
						placeholder='your pass' onChange={e=>setPass(e.target.value)} />
			<button onClick={()=>onLogin(login,pass)} disabled={(login.length!==0 && pass.length!==0)?false:true }>Send</button>
		</div>
	)
}

const CLoginForm = connect(null, {onLogin: actionFullLogin})(LoginForm)


const Spoiler = ({children}) => {
	const [open, setOpen] = useState(false);
	return(
		<div >
			<h3 onClick={e=>setOpen(!open)}>{open?'hide':'show'}</h3>
			{open && children}
		</div>
	)
}

function App() {
  return (
  	<Provider store={store}>
	    <div className="App">
	    <Timers />
	    
	      <Header />
	      <Main />
	      <Footer />
	    </div>
	</Provider>
  );
}

export default App;


