#!/usr/bin/env python3

import sys as _sys
import os as _os
import yaml as _yaml
import json as _json
import argparse as _argparse


def file_read(path):
	handle = open(path, "r")
	content = handle.read()
	handle.close()
	return content
	

def file_write(path, content):
	directory = _os.path.dirname(path)
	if (not _os.path.exists(directory)):
		_os.makedirs(directory, exist_ok = True)
	else:
		pass
	handle = open(path, "w")
	handle.write(content)
	handle.close()
	return content
	

def dict_merge(core, mantle, path = None):
	if (path is None):
		path = []
	result = {}
	for source in [core, mantle]:
		for (key, value_new, ) in source.items():
			path_ = (path + [key])
			type_new = type(value_new)
			if (not (key in result)):
				result[key] = value_new
			else:
				value_old = result[key]
				type_old = type(value_old)
				if (value_old is None):
					result[key] = value_new
				else:
					if (not (type_old == type_new)):
						raise ValueError(
							"type mismatch at path %s: %s vs. %s"
							% (
								".".join(path),
								str(type_old),
								str(type_new),
							)
						)
					else:
						if (type_old == dict):
							result[key] = dict_merge(value_old, value_new, path_)
						elif (type_old == list):
							result[key] = (value_old + value_new)
						else:
							result[key] = value_new
	return result
	

def main():
	## args
	argument_parser = _argparse.ArgumentParser()
	argument_parser.add_argument(
		"-m",
		"--main-file-path",
		type = str,
		dest = "main_file_path",
		default = "/etc/authelia/conf.d/main.json",
		metavar = "<main-file-path>",
	)
	argument_parser.add_argument(
		"-c",
		"--clients-directory-path",
		type = str,
		dest = "clients_directory_path",
		default = "/etc/authelia/conf.d/clients",
		metavar = "<clients-directory-path>",
	)
	argument_parser.add_argument(
		"-f",
		"--output-format",
		type = str,
		choices = ["json", "yaml"],
		dest = "output_format",
		default = "yaml",
		metavar = "<output-format>",
	)
	argument_parser.add_argument(
		"-o",
		"--output-path",
		type = str,
		dest = "output_path",
		default = "/etc/authelia/configuration.yml",
		metavar = "<output-path>",
	)
	args = argument_parser.parse_args()
	
	## exec
	data = {}
	### main
	if True:
		data_ = _json.loads(file_read(args.main_file_path))
		data = dict_merge(data, data_)
	### clients
	if True:
		for name in _os.listdir(args.clients_directory_path):
			data__ = _json.loads(file_read(_os.path.join(args.clients_directory_path, name)))
			data_ = {
				"identity_providers": {
					"oidc": {
						"clients": [data__]
					}
				}
			}
			data = dict_merge(data, data_)
	### postprocess
	if True:
		if (len(data["identity_providers"]["oidc"]["clients"]) <= 0):
			data["identity_providers"]["oidc"]["clients"].append(
				{
					"public": False,
					"id": "_dummy",
					"description": "not a real client; just here to make Authelia run",
					"authorization_policy": "one_factor",
					"secret": "",
					"scopes": [],
					"redirect_uris": [],
					"grant_types": [],
					"response_types": [],
					"response_modes": [],
				}
			)
		else:
			pass
	## output
	if True:
		if (args.output_format == "json"):
			output_content = _json.dumps(data, indent = "\t")
		elif (args.output_format == "yaml"):
			output_content = _yaml.dump(data)
		else:
			raise ValueError("invalid output format")
		file_write(args.output_path, output_content)
	

main()
