import { render } from "solid-js/web";
import { createState, createSignal, reconcile, createMemo } from "solid-js";
import { req, on } from './websocket';
import { create_deferred, c, Null } from './util';
import { state, setState } from './store';
import storage from 'kv-storage-polyfill';
import './index.css';
import NotFound from './pages/NotFound';
import NotAuthorized from './pages/NotAuthorized';
import NotAuthenticated from './pages/NotAuthenticated';
import Home from './pages/Home';
import User from './pages/User';
import Users from './pages/Users';
import Products from './pages/Products';

onpopstate = function() {
	setState('path', location.pathname.substring(1));
}

if(history.state === null) {
	history.replaceState({}, null);
}

function atHome() {return state.path.length === 0}
function atCart() {return state.path === 'cart/'}
const reservationRegex = /^\/((?<id>\d+)\/)?reservation\/$/;
const spyRegex = /^\/(?<id>\d+)$/;
const fuckRegex = /^((store\/(?<sid>\d+)(-(?<sslug>[A-Za-z0-9_]+))?\/(?<thing>product|review))|product)\/(?<rest>.*)$/;
const somethingRegex = /^(?<id>\d+)(-(?<slug>[A-Za-z0-9_]+))?(\/edit)?$/;
const atSpecificStoreRegex = /^(?<id>\d+)(-(?<slug>[A-Za-z0-9_]+))?\/(?<what>.+)/;

render(function() {
	const [wsSuccess, setWsSuccess] = createSignal(null);
	//disconnected, store, user are the three possible first events
	on('disconnected', function() {
		if(wsSuccess() === null) {
			setWsSuccess(false);
		}
	});
	on('store', function(how, data) {
		if(wsSuccess() === null) {
			setWsSuccess(true);
		}
		switch(how) {
			case 'replace':
				setState('stores', reconcile(data, {key: 'product_id'}));
				break;
			case 'add':
				setState('stores', state.stores.length, data);
				break;
			case 'remove':
				setState('stores', stores => stores.filter(store => store.id !== data));
				break;
			case 'update':
				setState('stores', state.stores.findIndex(store => store.id === data.id), data);//I think we do not want reconcile here since this is partial...
				break;
		}
	});
	on('user', function(how, data, why) {
		if(why) {//&& wsSuccess() so that alert isn't the first thing user sees on navigating to the site. up for discussion
			alert(why);
		}
		if(how === 'replace' && data !== null) {
			setState('user', reconcile(data));
		} else {//update || null
			setState('user', data);
		}
		if(wsSuccess() === null) {
			setWsSuccess(true);
		}
	});

	let email;
	const [passphrase, setPassphrase] = createSignal('');
	let remember_me;
	const [pp_visible, set_pp_visible] = createSignal(false);
	const [action, setAction] = createSignal('login');

	const atUser = createMemo(() => state.path.indexOf('user') === 0 ? state.path.substring(4) : false, false, true);
	const atReservations = createMemo(() => {
		const a = atUser();
		if(a === false) {
			return undefined;
		} else {
			return a.match(reservationRegex)?.groups;
		}
	}, undefined, (a, b) => a === b || typeof a === 'object' && typeof b === 'object' && a.id === b.id);
	const spy = createMemo(() => {
		const a = atUser();
		if(a === false) {
			return undefined;
		} else {
			return a.match(spyRegex)?.groups;
		}
	}, undefined, (a, b) => a === b || typeof a === 'object' && typeof b === 'object' && a.id === b.id);
	const fuck = createMemo(() => state.path.match(fuckRegex)?.groups, undefined, (a, b) => a === b || typeof a === 'object' && typeof b === 'object' && a.sid === b.sid && a.sslug === b.sslug && a.thing === b.thing && a.rest === b.rest);
	const something = createMemo(() => {
		const f = fuck();
		if(f === undefined) {
			return undefined;
		} else {
			return f.rest.match(somethingRegex)?.groups;
		}
	}, undefined, (a, b) => a === b || typeof a === 'object' && typeof b === 'object' && a.id === b.id && a.slug === b.slug);
	const atStore = createMemo(() => state.path.indexOf('store/') === 0 ? state.path.substring(6) : false, false, true);
	const atSpecificStore = createMemo(() => {
		const w = atStore();
		if(w === false) {
			return undefined;
		} else {
			return w.match(atSpecificStoreRegex)?.groups;
		}
	}, undefined, (a, b) => a === b || typeof a === 'object' && typeof b === 'object' && a.id === b.id && a.slug === b.slug && a.what === b.what);
	const gay = createMemo(() => fuck()?.sid === undefined || fuck()?.rest === 'new' || fuck()?.rest === 'edit' ? Null : Store, Null, true);
	function login_success() {
		storage.delete('carts');
		setPassphrase('');
	}
	return <Switch fallback={<>
		<header>
			<nav>
				<a class="pull" classList={{wow: atHome()}} onClick={c} href="/">home</a><br />
				<a classList={{wow: atCart()}} onClick={c} href="/cart/">cart</a><br />
				<a classList={{wow: state.path.indexOf('product') === 0}} onClick={c} href="/product/">products</a><br />
				<a classList={{wow: atStore() !== false}} onClick={c} href="/store/">stores</a><br />
				<Show when={state.user}>
					<a classList={{wow: atUser() !== false}} onClick={c} href="/user">{state.user.email}</a><br />
				</Show>
			</nav>
			<Show when={state.user} fallback={<>
				<form onsubmit={async e => {
					e.preventDefault();
					switch(action()) {
						case 'login':
						case 'register':
							req(action(), {
								remember_me: remember_me.checked,
								email: email.value,
								passphrase: passphrase(),
								carts: await storage.get('carts')
							}).then(login_success, alert);
							break;
						case 'login_otp':
							req('login_otp', {
								remember_me: remember_me.checked,
								carts: await storage.get('carts'),
								otp: passphrase()
							}).then(login_success, alert);
							break;
						case 'request_otp':
							req('request_otp', {email: email.value}).then(() => {
								alert('check your email');
								setPassphrase('');
							}, alert);
							break;
					}
				}}>
					<label>
						email
						<input required={action() !== 'login_otp'} type="email" placeholder="me@domain.com" ref={email} />
					</label>
					<label style="display: flex /*https://philipwalton.github.io/solved-by-flexbox/demos/input-add-ons/ this just makes the button height match and line up with the input field (2px woopdedoo)*/">
						passphrase
						<input class="longplaceholder" type={pp_visible() ? "text" : "password"} placeholder="a long passphrase is both easier to remember and more secure than a password!" value={passphrase()} onInput={e => setPassphrase(e.target.value)} />
						<button type="button" onClick={() => set_pp_visible(!pp_visible())}>{pp_visible() ? '👀' : '🙈'}</button>
					</label>
					<label><input type="checkbox" ref={remember_me}/>remember me</label>
					<button onClick={() => setAction('login')}>login</button>
					<button onClick={() => setAction('register')}>register</button>
					<button onClick={() => {
						if(passphrase()) {
							setAction('login_otp');
						} else {
							setAction('request_otp');
						}
					}}>{passphrase() ? 'login via code from email' : 'send login link to email'}</button>
				</form>
			</>}>
				<button type="button" onClick={() => req('logout')}>logout</button>
			</Show>
		</header>
		<main>
			<Switch>
				<Match when={atHome()}><Home /></Match>
				<Match when={atCart()}><Cart /></Match>
				<Match when={atUser() !== false}>
					<Switch fallback={NotFound}>
						<Match when={atUser().length === 0}>
							<Switch fallback={NotAuthenticated}>
								<Match when={state.user}>
									<User />
								</Match>
							</Switch>
						</Match>
						<Match when={atUser() === '/'}>
							<Switch fallback={NotAuthenticated}>
								<Match when={state.user?.god}>
									<Users />
								</Match>
								<Match when={state.user?.god === false}>
									<NotAuthorized />
								</Match>
							</Switch>
						</Match>
						<Match when={atReservations()}>
							<Switch fallback={NotAuthenticated}>
								<Match when={atReservations().id !== undefined && state.user?.god === false}>
									<NotAuthorized />
								</Match>
								<Match when={atReservations().id !== undefined && state.user?.god || atReservations().id === undefined && state.user}>
									<User_Reservations id={atReservations().id}/>
								</Match>
							</Switch>
						</Match>
						<Match when={spy()}>
							<Switch fallback={NotAuthenticated}>
								<Match when={state.user?.god}>
									<User id={spy().id} />
								</Match>
								<Match when={state.user?.god === false}><NotAuthorized /></Match>
							</Switch>
						</Match>
					</Switch>
				</Match>
				<Match when={fuck()}>
					<Dynamic component={gay()} id={fuck()?.sid} slug={fuck()?.sslug}>
						{/*@once*/<Switch fallback={NotFound}>
							<Match when={fuck()?.thing === 'review' && fuck()?.rest.length === 0}>reviews</Match>
							<Match when={(fuck()?.thing === 'product' || fuck()?.sid === undefined)}>
								<Switch fallback={NotFound}>
									<Match when={fuck()?.rest.length === 0}><Products /></Match>
									<Match when={something()}><Product id={something().id} />need switch</Match>
									<Match when={fuck()?.rest === 'new'}>new need switch</Match>
									<Match when={fuck()?.rest === 'edit'}>edit need switch</Match>
								</Switch>
							</Match>
						</Switch>}
					</Dynamic>
				</Match>
				<Match when={atStore() !== false}>
					<Switch fallback={NotFound}>
						<Match when={atStore().length === 0}>
							<Stores />
						</Match>
						<Match when={atStore() === 'new'}>
							<Switch fallback={NotAuthenticated}>
								<Match when={state.user?.god}><CreateStore /></Match>
								<Match when={state.user?.god === false}><NotAuthorized /></Match>
							</Switch>
						</Match>
						<Match when={atStore() === 'edit'}>
							<Switch fallback={NotAuthenticated}>
								<Match when={state.user?.god}>bulk / table edit of stores</Match>
								<Match when={state.user?.god === false}><NotAuthorized /></Match>
							</Switch>
						</Match>
						<Match when={atStore() === 'reservation/'}>
							<Switch fallback={NotAuthenticated}>
								<Match when={state.user?.god}>super aggregated stats to stroke ego</Match>
								<Match when={state.user?.god === false}><NotAuthorized /></Match>
							</Switch>
						</Match>
						<Match when={atSpecificStore()}>
							<Switch fallback={NotFound}>
								<Match when={atSpecificStore().what === 'edit'}>
									<Switch fallback={NotAuthenticated}>
										<Match when={state.user?.god || state.user?.acl?.[atSpecificStore().id]}>form here</Match>
										<Match when={state.user?.acl?.[atSpecificStore().id] === false}><NotAuthorized /></Match>
									</Switch>
								</Match>
								<Match when={atSpecificStore().what === 'reservation/'}>
									<Switch fallback={NotAuthenticated}>
										<Match when={state.user?.god || typeof state.user?.acl?.[atSpecificStore().id] === 'boolean'}>store_reservations id=atSpecificStore().id</Match>
										<Match when={state.user?.acl?.[atSpecificStore().id] === undefined}><NotAuthorized /></Match>
									</Switch>
								</Match>
							</Switch>
						</Match>
					</Switch>
				</Match>
			</Switch>
		</main>
		<footer>
			Sticky footer {new Date().getFullYear()}
		</footer>
	</>}>
		<Match when={wsSuccess() === false}>
			can't connect to backend. nothing is going to work
		</Match>
	</Switch>
}, document.body);