import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable }  from 'rxjs';
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
import { Order } from './order.model';
import { UserService } from '../user.service';
import { FullnodeService } from '../fullnode.service';
import { User } from '../user.model';
import { Owner } from '../owner.model';
import { LineItem } from '../items/lineitem.model';
import { newLineItem } from '../items/newlineitem.model';

import { ConfigData } from '../configdata';

var Buffer = require('buffer/').Buffer;

@Injectable({providedIn: 'root'})

export class OrderService {
	beUrl = ConfigData.Be_URL;
	private dataStore: {allOrders: Order[], user: User, order: Order, owner: Owner } = {
		allOrders: [],
		user:{
			address: '',
			session: '',
			blocktime: 0,
			pin: '',
			validated: false
		},
		owner: {
			_id: '',
			name: '',
			address: '',
			currency: 'usd',
			tax: false,
			taxValue: 0,
			vat: false,
			vatValue: 0,
			paid: false,
			zats: false,
			invoices: false,
			expiration: new Date(Date.now()).toISOString(),
			payconf: false,
			crmToken: ''
		},
		order: {
			address: '',
			session: '',
			timestamp: '',
			closed: false,
			currency: '',
			price: 0,
			total: 0,
			totalZec: 0,
			paid: false,
			externalInvoice: '',
			shortCode: '',
			lines: [
				{
					qty: 1,
					name: '',
					cost:0
				}
			]
		}
	};
	private _orderUpdated: BehaviorSubject<Order> = new BehaviorSubject(this.dataStore.order);
	public readonly orderUpdate: Observable<Order> = this._orderUpdated.asObservable();
	private _totalUpdated: BehaviorSubject<number> = new BehaviorSubject(this.dataStore.order.total);
	public readonly totalUpdate: Observable<number> = this._totalUpdated.asObservable();
	private _allOrdersUpdated: BehaviorSubject<Order[]> = new BehaviorSubject(this.dataStore.allOrders);
	public readonly allOrdersUpdate: Observable<Order[]> = this._allOrdersUpdated.asObservable();
	public userUpdate: Observable<User>;
	public ownerUpdate: Observable<Owner>;
	private reqHeaders: HttpHeaders;
	private reqParams: HttpParams;
	private session: null|string;

	constructor(
		private http: HttpClient,
		public fullnodeService: FullnodeService,
		public userService: UserService
	) {
		var auth = 'Basic ' + Buffer.from(ConfigData.UsrPwd).toString('base64');
		this.session = localStorage.getItem('s4z_token');
		this.reqHeaders = new HttpHeaders().set('Authorization', auth);
		this.reqParams = new HttpParams().append('session', this.session!);
		this.userUpdate = userService.userUpdate;
		this.ownerUpdate = userService.ownerUpdate;
		this.userUpdate.subscribe((user) => {
			this.dataStore.user = user;
			this.getOrder();
		});
		this.ownerUpdate.subscribe((owner) => {
			this.dataStore.owner = owner;
		});
	}

	getOrder() {
		let obs = this.http.get<{message: string, order: any}>(this.beUrl+'api/order', { headers:this.reqHeaders, params: this.reqParams, observe: 'response'});

		obs.subscribe((OrderDataResponse) => {
			if (OrderDataResponse.status == 200) {
				this.dataStore.order = OrderDataResponse.body!.order;
				this._orderUpdated.next(Object.assign({}, this.dataStore).order);
				this.dataStore.order.total = 0;
				for(var line of this.dataStore.order.lines) {
					this.dataStore.order.total += line.qty * line.cost;
				}
				this._totalUpdated.next(Object.assign({}, this.dataStore).order.total);
			} else {
				console.log('No order found');
			}
		});

		return obs;
	}

	getAllOrders(){
		var address = this.dataStore.user.address;
		const params = this.reqParams.append('address', address);
		let obs = this.http.get<{message: string, orders: any}>(this.beUrl+'api/allorders', { headers:this.reqHeaders, params:params, observe: 'response'});
		obs.subscribe((OrdersData) => {
			if (OrdersData.status == 200 ){
				console.log('getAllOrder:', OrdersData.body);
				this.dataStore.allOrders = OrdersData.body!.orders;
				this._allOrdersUpdated.next(Object.assign({}, this.dataStore).allOrders);
			} else {
				console.log('No orders');
			}
		});

		return obs;
	}

	addToOrder(lineItem: LineItem) {
		if(this.dataStore.order._id != null) {
			this.dataStore.order.lines.push(lineItem);
			let obs = this.http.post(this.beUrl+'api/order', { payload: this.dataStore.order }, { headers: this.reqHeaders, params: this.reqParams });
			obs.subscribe((orderData) => {
				this.getOrder();
			});
		} else {
			this.createOrder(lineItem);
		}
	}

	createOrder(lineItem: LineItem) {
		var order:Order = {
			_id: '',
			address: this.dataStore.user.address,
			session: this.dataStore.user.session,
			currency: this.dataStore.owner.currency,
			timestamp: new Date(Date.now()).toISOString(),
			closed: false,
			totalZec: 0,
			price: 0,
			total: 0,
			paid: false,
			externalInvoice: '',
			shortCode: '',
			lines: [lineItem]
		};
		let obs = this.http.post<{message: string, order: Order}>(this.beUrl+'api/order', {payload: order}, { headers: this.reqHeaders, params: this.reqParams });
		obs.subscribe((orderData) => {
			console.log('Created order');
			this.getOrder()
		});

		return obs;
	}

	cancelOrder(id: string) {
		let obs = this.http.delete<{message: string}>(this.beUrl+'api/order/'+id, { headers: this.reqHeaders, params: this.reqParams });

		obs.subscribe((OrderResponse) => {
			console.log('Order deleted');
			//this.getOrder();
			this.dataStore.order = {
				address: '',
				session: '',
				timestamp: '',
				closed: false,
				currency: '',
				total: 0,
				totalZec: 0,
				price: 0,
				paid: false,
				externalInvoice: '',
				shortCode: '',
				lines: [
					{
						qty: 1,
						name: '',
						cost:0
					}
				]
			};
			this._orderUpdated.next(Object.assign({}, this.dataStore).order);
		});

		return obs;
	}

	closeOrder(paid: boolean){
		this.fullnodeService.priceUpdate.subscribe((price) => {
			this.dataStore.order.price = price;
		});
		this.dataStore.order.closed = true;
		this.dataStore.order.paid = paid;
		let obs = this.http.post(this.beUrl+'api/order', {payload: this.dataStore.order}, { headers: this.reqHeaders });
		obs.subscribe((orderData) => {
			console.log('Closed order', orderData);
			this.dataStore.order = {
				address: '',
				session: '',
				timestamp: '',
				closed: false,
				currency: '',
				price: 0,
				total: 0,
				totalZec: 0,
				paid: false,
				externalInvoice: '',
				shortCode: '',
				lines: [
					{
						qty: 1,
						name: '',
						cost:0
					}
				]
			};
			this._orderUpdated.next(Object.assign({}, this.dataStore).order);
		});
		return obs;
	}

	updateOrder(itemid: number, iLines : newLineItem[]) {
		if(this.dataStore.order._id != null) {

			var item = {} as LineItem;
			this.dataStore.order.lines = [];
			for ( let i = 0; i < iLines.length; i++)
			  {
			  	 if ( i !== itemid )
			  	 {
				  	item = this.fillItemData(iLines[i].name, iLines[i].qty, iLines[i].cost);
//				  	console.log("Push => ", item);
 					this.dataStore.order.lines.push(item);
				 } 	
			  }	
			let obs = this.http.post(this.beUrl+'api/order', { payload: this.dataStore.order }, { headers: this.reqHeaders });
			obs.subscribe((orderData) => {
				this.getOrder();
			});
		}
	}

	fillItemData(iname:string, iqty: number, icost: number) : LineItem {

		const a = { name: iname, 
			        qty: iqty, 
			        cost: icost } as LineItem;
		return a;
	}


}
