import {  Resvg } from "@resvg/resvg-js";
import { promises } from "fs";
import { JSDOM } from "jsdom";
import * as d3 from "d3";
import yargs from "yargs/yargs";
import { hideBin } from "yargs/helpers";

import random from "random";

const xmlns = "http://www.w3.org/2000/xmlns/";
const xlinkns = "http://www.w3.org/1999/xlink";
const svgns = "http://www.w3.org/2000/svg";

import {RADIUS_OPTS, DotMaker} from './src/components/dots.js';
import {PALETTES, colour_to_text} from './src/components/palettes.js';

const CELL = 10;
const MAG = 2;
const WIDTH = 20;
const HEIGHT = WIDTH;

function randomise_params() {
	const palette_name = random.choice(Array.from(PALETTES.keys()));
	const palette_fn = PALETTES.get(palette_name);
	const palette = palette_fn();
	const patterns = [1,2].map((n) => { return {
		i: n,
		colour: palette[n],
		m: random.choice([1, 2, 3, 4, 5]),
		n: random.choice([1, 2, 3, 4, 5]),
		f: random.choice(RADIUS_OPTS),
		r: random.float(0, 0.4),
	}});
	return {
		background: palette[0],
		palette: palette_name,
		patterns: patterns
	}
}


function image_description(params) {
	const bgc = colour_to_text(params.background);
	const dotc = params.patterns.map((p) => colour_to_text(p.colour));
	const a = bgc.match(/^[aeiou]/) ? 'an' : 'a';
	return `A pattern of ${dotc[0]} and ${dotc[1]} dots on ${a} ${bgc} background`;

}


function poptimal_svg(params) {
	const window = new JSDOM().window;
	const document = window.document;
	const container = d3.select(document.body).append("div");

	const dm = new DotMaker(WIDTH);

	const svg = container.append("svg")
	  .attr("width", WIDTH * CELL * MAG)
	  .attr("height", HEIGHT * CELL * MAG)
	  .attr("viewBox", [ 0, 0, WIDTH, HEIGHT ]);

	const background = svg.append("rect")
	  .attr("x", 0)
	  .attr("y", 0)
	  .attr("width", WIDTH)
	  .attr("height", WIDTH)
	  .attr("fill", params.background);


	params.patterns.map((p) =>  {
		const dots = dm.dots(1 / p.m, p.n);
		const dots_g = svg.append("g")
	  			.attr("id", `dots${p.i}`);
	
		dots_g.selectAll("circle")
		  .data(dots)
		  .join("circle")
		  .attr("r", (d) => dm.radius(d, p.f, p.r))
		  .attr("fill", p.colour)
		  .attr("cx", (d) => d.x)
		  .attr("cy", (d) => d.y);
	});
 
	const node = svg.node();

  	node.setAttributeNS(xmlns, "xmlns", svgns);
  	node.setAttributeNS(xmlns, "xmlns:xlink", xlinkns);
  	const serializer = new window.XMLSerializer;
  	return serializer.serializeToString(node);

}


async function post_image(image, alt_text, cf) {
	const status_url = `${cf.base_url}/api/v1/statuses`;
	const media_url = `${cf.base_url}/api/v1/media`;
	const headers = {
		'Authorization': `Bearer ${cf.access_token}`,
	};
	const rawData = await promises.readFile(image);
	const blob = new Blob([rawData]);
	const fd = new FormData();
	fd.set('description', alt_text);
	fd.set('file', blob, image, 'text/png');
	const resp = await fetch(media_url, {
		method: 'POST',
		headers: headers,
		body: fd
	});

	const bodyjson = await resp.text();
	const response = JSON.parse(bodyjson);
	const media_id = response["id"];

	headers['Accept'] = 'application/json';
	headers['Content-Type'] = 'application/json';
	const resp2 = await fetch(status_url, {
		method: 'POST',
		headers: headers,
		body: JSON.stringify({ media_ids: [ media_id ] })
	});
	const bodyjson2 = await resp2.text();

}

async function main() {
	const argv = yargs(hideBin(process.argv))
		.usage("Usage: -s SIZE -o output.png -c config.json")
		.default('s', 1200)
		.default('c', 'config.json').argv;

	if( argv.t ) {
		const blue = d3.rgb(0, 0, 255);
		const name = await colour_to_text(blue, "./rgb.txt");
		console.log(name);
		process.exit();
	}

	const cfjson = await promises.readFile(argv.c);
  	const cf = JSON.parse(cfjson);

  	const fn = argv.o || String(Date.now()) + '.png';

  	const imgfile = cf['working_dir'] + '/' + fn;

	const params = randomise_params();
	const alt_text = image_description(params);

	const svg = poptimal_svg(params);
	const opts = {
    	background: 'rgba(255, 255, 255, 1.0)',
    	fitTo: {
      		mode: 'width',
      		value: argv.s,
    	},
    };

  	const resvg = new Resvg(svg, opts);
 	const pngData = resvg.render();
  	const pngBuffer = pngData.asPng();

  	await promises.writeFile(imgfile, pngBuffer);
	console.log(imgfile);
	console.log(alt_text);
  	if( cf['base_url'] ) {
  		await post_image(imgfile, alt_text, cf);
  	}
}



main();