import React from 'react';
import LinkManager from 'modularity-front';
import Modularity from 'modularity-front';
import {Card, Col,Row} from 'react-materialize';
import './CartPage.css';
import API from '../../Services/API';
import Repository from '../../Services/Repository';
import UserService from '../../Services/UserService';
import Step from '@material-ui/core/Step';
import StepLabel from '@material-ui/core/StepLabel';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import CustomTable from '../../Modules/CustomTable';
import Form from '../../Modules/Form';
import TableModule from  '../../Modules/Table';
import ArraySelector from  '../../Modules/ArraySelector';
import AddressBox from  '../../Modules/AddressBox';
import Addresses from  '../../HigherModules/AddressesDisplay';
import Toast from '../../helpers/Toast';

import Dictionary from '../../Services/DictionaryService';

import ClientInputs from '../../Inputs/ClientInput';
import AddressInputs from '../../Inputs/AddressInput';

import Stepper from '../../Modules/Stepper';

// import braintree from 'braintree-web';
const braintree = window.braintree;


let CLIENT_TOKEN, INSTANCE;

let Module = Modularity.Module;

class CartPage extends Modularity.Module {
	constructor(props) {
		super(props);
		this.state = {
			activeStep:0,
			products:[],
			productHeaders:{
				'#': '-index-',
				image:"image",
				Name:"name",
				"Item Price": {
					field: "price",
					suffix: " €"
				},
				Quantity:"quantity",
				Total: {
					field: "amount",
					suffix: " €"
				}
			},
			selectedAddress: {},
			selectedBillingAddress: {},
			selectedShipping: {},
			user: {},
			clientInputs: {}
		}

		this.formRef = React.createRef();

		this.api = new API('/orders', this.Token.value);
		this.addressRepo = new Repository('addresses', this.Token.value);
		this.accountRepo = new Repository('accounts', this.Token.value);
		this.userRepo = new UserService({
            Token: (t) => {
            }
        });
		this.state = { 
			...this.state,
			...(this._load())
		};
		this.Products.onUpdate((data) => {
			this.setState(this._load());
		});

		this.Token.onUpdate((token) => this.handleToken(token));
		this.handleToken();
	}


	_product_to_table(prods) {
		return Object.keys(prods).map((key,index) => {
			let { name , price , quantity , image} = prods[key]
			return {
				id: key,
				image,
				name,
				price: parseFloat(price.toFixed(2)),
				quantity,
				amount: parseFloat((price * quantity).toFixed(2))
			};
		})
	}

	_load(withShipping = false) {
		let products = this._product_to_table(this.Products.value || {});
		let total = Object.keys(this.Products.value || {}).reduce((tot, item) => 
		tot + (this.Products.value[item].price * this.Products.value[item].quantity)
		, (withShipping ? (this.state.selectedShipping.price || 0) : 0)); //start with shipping
		let fpa = 0.24 * total;
		return { products, total, fpa };
	}

	routeMatch() {
		return this.RoutingSystem.getRoute().url.startsWith(this.baseURL.value);
	}

	requestClientToken(token) {
		this.baseAPI = new API("",token);
		this.baseAPI.get("/client_token")
		.then((res) => {
			let ctoken = res.clientToken;
			this.CLIENT_TOKEN = ctoken;
			this.showPayment();
		})
	}

	handleToken() {
		if(this.Token.value === "missing" 
			&& this.RoutingSystem.getRoute().url !== "/login" 
			&& this.routeMatch()) {
			this.CoreSystem.go('/login', { ref: this.RoutingSystem.getRoute().url }, true)
		}
		if(this.Token.value) {
			this.requestClientToken(this.Token.value);
		}
		this.api.setToken(this.Token.value);
		this.accountRepo.setToken(this.Token.value);
		this.addressRepo.setToken(this.Token.value);
		this.getUserData();
	}

	showPayment() {
		braintree.dropin.create({
			authorization: this.CLIENT_TOKEN,
	      	container: '#dropin-container',
	      	paypal: {
	      		flow: 'vault'
	      	}
	    }, function (createErr, instance) {
	    	INSTANCE = instance;
	    })
	}

	makePayment() {
        return new Promise((resolve,reject) => {
        	INSTANCE.requestPaymentMethod((err, payload) => {
          		// Submit payload.nonce to your server
          		if(err) {
          			return reject(err);
          		} 
          		resolve(payload);
        	});
        });
	}

	makeOrder() {
		// FIX PRICE only 2 decimal places
		return this.makePayment()
		.then((payload) => {
			let products = this.state.products;
			let amount = parseFloat(this.state.total.toFixed(2));
			let nonce = payload.nonce;
			let customer = this.state.customer;
			let shipping = this.state.shipping;
			let ShippingID = this.state.selectedShipping.id;
			let AddressID = this.state.selectedAddress.id;
			this.api.post('/submit', {
				products,
				amount,
				nonce,
				customer,
				Shipping_id: ShippingID,
				Addresses_id: AddressID
			}).then((res) => {
				console.log(res);
				alert("Success")
				this.CoreSystem.go('/user/orders');
			})
			.catch((err) => {
				alert(err);
			});
		})
	}

	

	makeInputs(struct) {
		let res = {...struct};
		let user = this.state.user;
		if(!user.Account) return res;
		let acc = user.Account;
		for(var i in res) {
			res[i].value = acc[i] || '';
		}
		return res;
	}
	
	makeAddresses() {
		let user = this.state.user;
		if(!user.Addresses) return [];

		return user.Addresses || [];
	
	}

	makeAddress(struct, address) {
		if(!address) return struct;
		for(var i in struct) {
			struct[i].value = address[i] || '';
		}
		return struct;
	}

	updateAccount(acc) {
		this.setState({
			formAccount: acc
		});
	}

	getUserData() {
		return this.userRepo.getUser(this.Token.value).then((user) => this.setState({user}))
		.then(() => this.makeInputs(ClientInputs))
		.then((clientInputs) => this.setState({ clientInputs }));
	}

	verifyOrderDetails() {
		Toast.clear();
		let accid = this.state.user.Account && this.state.user.Account.id;
		return Promise.resolve(true)
		.then(() => this.state.formAccount && accid && this.accountRepo.update(accid, this.state.formAccount))
		.then(() => this.getUserData())
		.then(() => {
			if (!this.state.selectedAddress || !this.state.selectedAddress.id) {
				// this.CoreSystem.go('/orders/verify');
				Toast.warning(Dictionary.get("Select address!"));
				throw 'no selected Address'; 
			}

			if (!this.state.selectedBillingAddress || !this.state.selectedBillingAddress.id) {
				// this.CoreSystem.go('/orders/verify');
				Toast.warning(Dictionary.get("Select billing address!"));
				throw 'no selected Address'; 
			}
			if (!this.state.selectedShipping || !this.state.selectedShipping.id) {
				// this.CoreSystem.go('/orders/verify');
				Toast.warning(Dictionary.get("Select shipping method!"));
				throw 'no selected Shipping';
			}
		});
	}

	onNext(step) {
		console.log(step);
	}

	getSteps(){
		return [
		{	title: 	Dictionary.get("Cart"),
			url: 	'/orders',
			content: this.getStepContent(0),
			button: Dictionary.get("Checkout"),
			resolve: () => {
				this.setState(this._load(false))
			}
		},
		{
			title: 	Dictionary.get("Order Info"), 
			url: 	'/orders/verify', 
			content: this.getStepContent(1),
			button: Dictionary.get("Payment"),
			resolve: () => this.getUserData()
		},
		{
			title: 	Dictionary.get("Payment"),
			url: 	'/orders/payment', 
			content: this.getStepContent(2),
			button: Dictionary.get("Finish"),
			resolve: () => {
				this.setState(this._load(true));
				return this.verifyOrderDetails();
			},
			postResolve: () => this.showPayment()
		}];
	}

	getStepContent(stepIndex) {
	  switch (stepIndex) {
	    case 0:
	      return (
	      	<div>
		      	<div className="headers"></div>
		      	<TableModule TableData={[...this.state.products, 
		      			{quantity: "ΦΠΑ", amount: (this.state.fpa || 0).toFixed(2)},
			      		{quantity: <b>{Dictionary.get("Total")}</b>, amount: <b>{this.state.total.toFixed(2) + ' €'}</b>}
			      	]}
		      		TableHeaders = {this.state.productHeaders} TableClass="products_table"/>
	      	</div>);
	    case 1:
	      // let addresses = this.makeAddresses();
	      return (
	      	<div>
	      		<div className="headers">{Dictionary.get("Please fill your Information")}</div>
	      		<Card>
	      			<Form FormInputs={this.state.clientInputs} activeButton = {false} formData={(data) => this.updateAccount(data)} ref={this.formRef}/>
	      		</Card>
	      		<div className="headers">{Dictionary.get("Select delivery address")}</div>
	      		<Addresses service={this.addressRepo} update={(v) => this.setState({__V:v})}
	      		onSelect={(selectedAddress) => {
				 	this.setState({selectedAddress});
				}}/>
				<div className="headers">{Dictionary.get("Select billing address")}</div>
				<Addresses service={this.addressRepo} update={(v) => this.setState({__V:v})}
	      		onSelect={(selectedBillingAddress) => {
				 	this.setState({selectedBillingAddress});
				}}/>
				<Shippings onSelect={(selectedShipping) => {
				 	this.setState({selectedShipping});
				}}/>
	    	</div>);
	    case 2:
	      return (
	      	<div>
	      		<div>
			      	<div className="headers"></div>
			      	<TableModule TableData={[
			      		...this.state.products,
			      		{quantity: Dictionary.get("Shipping Cost"), amount: (this.state.selectedShipping.price || 0).toFixed(2)},
			      		{quantity: "ΦΠΑ", amount: this.state.fpa.toFixed(2)},
			      		{quantity: <b>{Dictionary.get("Total")}</b>, amount: <b>{this.state.total.toFixed(2) + ' €'}</b>}
			      	]} TableHeaders = {this.state.productHeaders} TableClass="products_table"/>
		      	</div>
	      		<span>{Dictionary.get("Payment")}</span>
	      		<div id="dropin-container"></div>
	      		<Button onClick={() => this.makeOrder()}>{Dictionary.get("Submit order")}</Button>
	      	</div>);
	  }
	}

	
	render() {
		return (
			<div className="stepper_container">
	        	<Stepper className="row stepper" steps={this.getSteps()}  baseURL={this.baseURL.value}
	        		onNext={(step) => this.onNext(step)} lock={this.state.lock}/>
		      	{super.render()}
		    </div>
		);	    
	}
}

class Shippings extends React.Component {
	constructor(props) {
		super(props);
		this.state = {
			shippings: [],
			selected: {}
		};
		this.repo = new Repository('shipping');
		this.repo.getPage(1,1000).then((shippings) => this.setState({shippings}));
	}

	select(selected) {
		this.setState({selected});
		this.props.onSelect && this.props.onSelect(selected);
	}

	render() {
		let selected = this.state.selected;
		let shippings = this.state.shippings;
		return <div className="shipping-items">
			<div className="headers">{Dictionary.get("Select shipping method")}</div >
			{shippings.map((ship) => {
				return <div key={ship.id} className={"card cursor shipping-item " + (ship.id === selected.id ? 'selected' : '')} 
						onClick={() => this.select(ship)}>
					<div className='name'>{ship.name}</div>
					<div className='price'>+ {ship.price.toFixed(2)} €</div>
				</div>
			})}
		</div>;
	};
}

CartPage.EditPosition = "center";
CartPage.Inputs = {
	Products: {
		type: Module.Types.Object
	},
	Token: {
		type: Module.Types.Text
	},
	baseURL: {
		type: Module.Types.Text,
		defaultValue: "/orders"
	}
}



CartPage.Outputs = {
	selectedProduct:{

	}
}

CartPage.Category = "Sxoinas Packages";
export default CartPage;