import "./App.css";
import "bootstrap/dist/css/bootstrap.min.css";
import * as base64 from "base-64";
import { Client } from "jmap-client-ts";
import { FetchTransport } from "jmap-client-ts/lib/utils/fetch-transport";

import { IAccount, ISession } from "./types";
import AppLayout from "./AppLayout";
import AuthModal from "./AuthModal";
import React from "react";

interface IAuth {
	email: string;
	password: string;
}

interface ILocation {
	accountId: string;
}

type AppState = {
	auth: IAuth;
	location: ILocation;
	session: ISession | null;
};

type AppProps = {};

class App extends React.Component<AppProps, AppState> {
	account(): IAccount | null {
		if (!(this.state.session && this.state.session.accounts)) return null;
		return this.state.session.accounts[this.state.location.accountId];
	}
	client: Client | null = null;
	state: AppState = {
		auth: { email: "", password: "" },
		location: { accountId: "" },
		session: null,
	};

	// Make the request to get system metadata
	doLogin(auth: IAuth) {
		const domain = auth.email.split("@")[1];
		const well_known_url = "https://" + domain + "/.well-known/jmap";
		const basic_auth =
			"Basic " + base64.encode(auth.email + ":" + auth.password);

		this.client = new Client({
			accessToken: "fake token",
			httpHeaders: { Authorization: basic_auth },
			sessionUrl: well_known_url,
			transport: new FetchTransport(fetch.bind(window)),
		});

		this.client
			.fetchSession()
			.then(() => {
				console.log("Session received");

				// For the type checker
				if (!this.client) return;

				const session = this.client.getSession();
				this.setState({
					...this.state,
					session: {
						...session,
						accounts: Object.fromEntries(
							Object.entries(session.accounts).map(([key, account]) => [
								key,
								{ ...account, id: key.toString(), mailboxes: [] },
							]),
						),
					},
				});
			})
			.catch((error) => console.error(error));

		return;
	}

	onHashChange() {
		console.log(window.location.hash);
		const hash = window.location.hash.substring(1);
		this.setState({
			...this.state,
			location: { accountId: hash },
		});
	}
	// When the user provides credentials
	onLogin(email: string, password: string) {
		// Store the provided credentials for now
		this.setState({
			...this.state,
			auth: {
				email: email,
				password: password,
			},
		});
		localStorage.setItem("auth", JSON.stringify(this.state.auth));
		this.doLogin({ email, password });
	}

	loadAuth() {
		const data = localStorage.getItem("auth");
		if (!data) return;
		const auth = JSON.parse(data);
		this.setState({
			...this.state,
			auth: auth,
		});
		if (this.client == null) {
			this.doLogin(auth);
			return;
		}
	}

	componentDidMount() {
		window.addEventListener(
			"hashchange",
			() => {
				this.onHashChange();
			},
			false,
		);
		this.loadAuth();
		this.onHashChange();
	}

	componentWillUnmount() {
		window.removeEventListener(
			"hashchange",
			() => {
				this.onHashChange();
			},
			false,
		);
	}

	render() {
		return (
			<div className="App">
				{this.state && this.state.session ? (
					<AppLayout
						account={this.account()}
						accounts={this.state.session.accounts}
						client={this.client}
					/>
				) : (
					<AuthModal onLogin={this.onLogin}></AuthModal>
				)}
			</div>
		);
	}
}

export default App;
