Object.entries(require('./common.js')).forEach(([name, exported]) => global[name] = exported);
const url = "https://albertacannabis.org/";
const range = /(\d*\.?\d+)(?:[-−](\d*\.?\d+))?\s*(?:[A-Za-z%]+)/;
const quantityregex = /(?:(\d+)\s*(?:[Xx])\s*)?(\d*\.?\d+)\s*(?:[A-WYZa-wyz]+)/;
let anticaptcha = require('./anticaptcha.js')(process.env.ANTICAPTCHA_TOKEN);
const writeFile = util.promisify(require('fs').writeFile);
function captcha() {
	return new Promise((resolve, reject) => {
		anticaptcha.getBalance((err, balance) => {
			if(err) {
				reject(err);
			} else {
				if(balance > 0) {
					console.log(balance + ' USD');
					anticaptcha.createTaskProxyless((err, taskId) => {
						if(err) {
							reject(err);
						} else {
							console.log(taskId);
							anticaptcha.getTaskSolution(taskId, (err, taskSolution) => {
								if(err) {
									reject(err);
								} else {
									resolve(taskSolution);
								}
							});
						}
					});
				} else {
					reject('insufficient funds to beat captcha');
				}
			}
		});
	});
}

async function cookieString(page) {
	let cookieString = `"Cookie: `;
	let cookies = await page.cookies();
	for(let i = 0; i < cookies.length; ++i) {
		if(cookies[i].name === 'ASP.NET_SessionId') {
			cookieString += `ASP.NET_SessionId=${cookies[i].value}; `;
		} else if(cookies[i].name === '__RequestVerificationToken') {
			cookieString += `__RequestVerificationToken=${cookies[i].value}; `;
		} else if(cookies[i].name === '.ASPXAUTH') {
			cookieString += `.ASPXAUTH=${cookies[i].value}; `;
		}
	}
	return cookieString.slice(0, -2) + `"`;
}

async function login(page, c, attempt) {
	await page.goto(url + 'login');
	await Promise.all([
		page.waitForNavigation().then(async response => {
			response = await response.json();
			if(!response.Success) {
				if(attempt > 4) {
					console.error(response);
					process.exit(1);
				}
				if(++attempt % 2) {
					await new Promise(resolve => setTimeout(resolve, 1000));
					await login(page, c, attempt);
				} else {
					await login(page, await captcha(), attempt);
				}
			}
		}),
		page.evaluate((solution, usr, pass) => {
			let f = document.forms['LoginForm'];
			let e = f.elements;
			e['UserName'].value = usr;
			e['UserName'].removeAttribute('disabled');
			e['Password'].value = pass;
			e['Password'].removeAttribute('disabled');
			let re = document.createElement('input');
			re.setAttribute('type', 'text');
			re.setAttribute('name', 'g-recaptcha-response');
			re.setAttribute('value', solution);
			f.append(re);
			f.submit();
		}, c, process.env.AB_USER, process.env.AB_PASS)
	]);
}

async function saveCookie(page) {
	let cookies = await page.cookies();
	for(let i = 0; i < cookies.length; ++i) {
		cookies[i].expires = 2147483647;
	}
	await writeFile('ab.json', JSON.stringify(cookies, null, '\t'));
}

(async function() {
	let start = new Date();
	const browser = await puppeteer.launch({
		args: ["--no-sandbox"],
		headless: false
	});
	await postgres.connect();
	await postgres.query('begin');
	let storeID = (await postgres.query(`select ios_store_id('ab', 'alberta', 'canada', _url => $1, _delivery => true, _prepayment => true)`, [url])).rows[0].ios_store_id;
	const page = await mnmalism((await browser.pages())[0]);
	let ua = await page.evaluate('navigator.userAgent');
	try {
		await page.setCookie(...require('./ab.json'));
	} catch(e) {}
	await page.goto(url);
	let csrf = await page.$eval('#_CRSFform > input[type=hidden]', el => el.value);
	// let fuckoff;
	// try {
	// 	fuckoff = Object.values(groupBy(JSON.parse(require('fs').readFileSync('wow', {encoding: 'string'})).Variants, 'ProductId'))
	// } catch(e) {}
	let curl;
	// if(!fuckoff) {
		curl = exec(`curl "https://albertacannabis.org/api/cxa/CatalogExtended/GetProductList" -H ${await cookieString(page)} -H "User-Agent: ${ua}" -H "__RequestVerificationToken: ${csrf}" --data "ps=1000&f=in_stock=true|false&sd=Asc&cci={DAAC337F-EC42-9DD5-33BC-851875C99BEB}&ci={C8173B3F-26C8-41AB-B042-9CAAD37B543B}&__RequestVerificationToken=${csrf}"`)// --compressed
			.then(raw => [Object.values(groupBy(JSON.parse(raw.stdout).Variants, 'ProductId')), new Date()]);
	// } else {
	// 	curl = [fuckoff, new Date()];
	// }
	if(await page.$eval('#header', el => /login/i.test(el.textContent))) {
		anticaptcha.setWebsiteURL(url + 'login');
		anticaptcha.setWebsiteKey('6LdU65cUAAAAAKzOnF9G9ken97cmhNWGl66lrGJE');
		anticaptcha.setUserAgent(ua);
		await login(page, await captcha(), 0);
		await saveCookie(page);
	}
	console.log('logged in at: ', new Date());
	let [products, APItouch] = await curl;
	console.log('retrieved products from api at: ', APItouch);
	let i = 0;
	let progress = 0;
	let gas = [];
	require('fs').writeFileSync('wow', JSON.stringify(products));
	//cliProgressBar.start(products.length, progress);
	async function deal(p) {
		while(i < products.length) {
			let idx = i++;
			let type;
			switch(products[idx][0].Format) {
				case 'Dried Flower':
				case 'Milled Flower':
					type = 'flower';
					break;
				case 'Pre-Rolls':
					type = 'preroll';
					break;
				case 'Prefilled Vape Cartridge':
				case 'Vape Kit':
					type = 'cartridge';
					break;
				case 'Disposable Vape Pen':
					type = 'disposable';
					break;
				case 'Oil':
					type = 'oil';
					break;
				case 'Oral Spray':
					type = 'spray';
					break;
				case 'Capsules':
				case 'Soft Gel':
					type = 'capsule';
					break;
				case 'Tea Bags':
					type = 'tea';
					break;
				case 'Iced Tea':
				case 'Sodas':
				case 'Sparkling Beverages':
					type = 'rtd';
					break;
				case 'Distillate Powder':
					type = 'powder';
					break;
				case 'Distillate Liquid':
					type = 'liquid';
					break;
				// case '':
				// 	type = 'shot';
				// 	break;
				case 'Soft Chews':
					type = 'gummy';
					break;
				case 'Hard Candy':
					type = 'mint';
					break;
				case 'Chocolate':
					type = 'chocolate';
					break;
				case 'Cookies':
					type = 'baked';
					break;
				default:
					//cliProgressBar.update(++progress);
					++progress;
					continue;
			}
			await goto(p, url, products[idx][0].Link.substring(1), 0);
			let [producer, brand, name, join_name, hack] = normalize(
				products[idx][0].Brand,
				products[idx][0].DisplayName,
				type,
				await p.$eval('.sku-lp', e => e.textContent.trim())
			);
			let blend = false;
			if(products[idx][0].Type === 'Blend') {
				blend = true;
				let fuck = products[idx][0].Strain.match(/hybrid|indica|sativa/i)?.[0]?.toLowerCase();
				if(fuck) {
					products[idx][0].Type = fuck;
				} else {
					products[idx][0].Type = 'hybrid';
					//console.log('shame', products[idx][0].Link);
					//cliProgressBar.update(++progress);
					//continue;
				}
			}
			if(/blend/i.test(products[idx][0].Strain)) {
				blend = true;
			}
			let terpenes = await p.$$eval('.item-terpene > h3', els => {
				for(let j = els.length - 1; j >= 0; --j) {
					els[j] = els[j].textContent;
					if(els[j] === 'Other Terpenes') {
						els.splice(j, 1);
					} else {
						els[j] = els[j].replace(/(\d*\.?\d+)([-−](\d*\.?\d+))?\s*([A-Za-z%]+)/, '').replace(/\s*\(.*\)\s*/, '').trim();
					}
				}
				return els;
			});
			try {
				terpenes.append((await p.$eval('#otherTerpenesInfoTip', el => el.textContent)).split(';'));
			} catch(e) {}
			let productID = (await postgres.query(`select ios_product_id($1, $2, $3, $4, $5, $6, $7, $8, $9, true, $10, $11)`, [
				producer,
				brand,
				name,
				join_name,
				type,
				products[idx][0].Type.toLowerCase(),
				blend,
				blend ? null : strain_clean(products[idx][0].Strain),
				await p.$eval('.description', e => e.textContent.trim()),
				terpenes,
				brand === 'dosist' ? '.00225' : null
			])).rows[0].ios_product_id;
			for(let j = 0; j < products[idx].length; ++j) {
				let portions = 1;
				let quantity = products[idx][j].Quantity;
				if(type === 'preroll' || type === 'capsule') {
					gas.push(await p.$eval('#' + products[idx][j].VariantId, e => JSON.parse(e.dataset.variantData).disambiguatingdescription));
					[,portions, quantity] = (await p.$eval('#' + products[idx][j].VariantId, e => JSON.parse(e.dataset.variantData).disambiguatingdescription)).match(quantityregex) ?? [];
					portions = portions ?? 1;
					if(!quantity) {
						quantity = products[idx][j].Quantity
					}
				}
				let params = [productID, portions, quantity];
				let [variantID, g] = (await postgres.query(
					`select ios_variant_id($1, $2, $3${type === 'oil' || type === 'spray' || type === 'capsule' ? `, _gram_equivalency => $${params.push(await p.$eval('#' + products[idx][j].VariantId, e => JSON.parse(e.dataset.variantData).equivalency))}` : ''})`,
					params
				)).rows[0].ios_variant_id.slice(1, -1).split(',');
				//warning gram equivalency does not match
				try {
					let [,minTHC, maxTHC] = products[idx][j].Thc.match(range);
					let [,minCBD, maxCBD] = products[idx][j].Cbd.match(range);
					await postgres.query(
						`insert into menu_item (
							variant_id,
							store_id,
							cbd,
							thc,
							price,
							stock,
							path
						) values (
							$1,
							$2,
							$3,
							$4,
							$5,
							$6,
							$7
						) on conflict (variant_id, store_id) do update set cbd = excluded.cbd, thc = excluded.thc, price = excluded.price, stock = excluded.stock`,
						[
							variantID,
							storeID,
							`[${minCBD ?? maxCBD ?? 0},${maxCBD ?? minCBD ?? 0}]`,
							`[${minTHC ?? maxTHC ?? 0},${maxTHC ?? minTHC ?? 0}]`,
							products[idx][j].AdjustedPrice.replace('$', '').split(/\s+/)[0],
							await p.$eval('[data-variantId="' + products[idx][j].VariantId + '"]', el => el.getAttribute('data-count')),
							products[idx][j].Link
						]
					);
				} catch(e) {
					console.log(products[idx][j]);
					console.log(						`[${minCBD},${maxCBD}]`,
						`[${minTHC},${maxTHC}]`,
						products[idx][j].AdjustedPrice.replace('$', '').split(/\s+/)[0],
						await p.$eval('[data-variantId="' + products[idx][j].VariantId + '"]', el => el.getAttribute('data-count')),
						products[idx][j].Link);
				}
			}
			//cliProgressBar.update(++progress);
			++progress;
		}
	}
	await Promise.all([
		deal(page),
		deal(await mnmalism(await browser.newPage())),
		deal(await mnmalism(await browser.newPage()))
	]);
	console.log(products.length, progress)
	require('fs').writeFileSync('gas', JSON.stringify(gas));
	await saveCookie(page);
	await browser.close();
	await postgres.query('commit');
	await postgres.end();
})();