'use strict';

const fs = require('node:fs');
const https = require('node:https');
const http = require('node:http');
const util = require('node:util');
const exec = util.promisify(require('node:child_process').exec);

const { getBin, getPlatform } = require('../include');
const { mkdir, rmdir, rm } = require('./files');


const protocols = { http, https };


const installRecursive = async (url, count = 1) => {
	try {
		const proto = protocols[url.match(/^https?/)[0]];
		
		const response = await new Promise((res, rej) => {
			const request = proto.get(url, (response) => res(response));
			request.on('error', (err) => rej(err));
		});
		response.on('error', (err) => { throw err; });
		
		// Handle redirects
		if ([301, 302, 303, 307].includes(response.statusCode)) {
			if (count < 5) {
				return installRecursive(response.headers.location, count + 1);
			}
			console.warn(url);
			throw new Error('Error: Too many redirects.');
		}
		
		// Handle bad status
		if (response.statusCode !== 200) {
			console.warn(url);
			throw new Error(`Response status was ${response.statusCode}`);
		}
		
		await rmdir(getBin());
		await mkdir(getBin());
		
		const packPath = `${getBin()}/${getPlatform()}.gz`;
		
		await new Promise((res, rej) => {
			const packWriter = fs.createWriteStream(packPath);
			packWriter.on('error', (err) => rej(err));
			packWriter.on('finish', () => res());
			response.pipe(packWriter);
		});
		
		const { stderr } = await exec(`tar -xzf ${packPath} --directory ${getBin()}`);
		if (stderr) {
			console.warn(stderr);
		}
		
		await rm(packPath);
		return true;
	} catch (error) {
		console.error(error.message);
		return false;
	}
};


const install = async (folder) => {
	const url = `${folder}/${getPlatform()}.gz`;
	return installRecursive(url);
};

module.exports = { install };