#!/usr/bin/env python3

import bcrypt
import yaml
import re
import json
import os
import sys
from typing import Optional, Dict, Any, List

def _read_user_passwords(password_file_path):
    """Read user passwords from file and return a dictionary of username to hashed password."""
    try:
        with open(password_file_path, "r") as f:
            lines = f.readlines()
    except FileNotFoundError:
        print(f"Warning: Password file {password_file_path} not found. Skipping user authentication.")
        return None

    users = {}
    for line in lines:
        line = line.strip()
        if not line or line.startswith("#"):
            continue
        try:
            username, password = [item.strip() for item in line.split(":", 1)]
            hashed_password = bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt())
            users[username] = hashed_password.decode()
        except ValueError:
            print(f"Warning: Invalid line format in password file: {line}")
            continue

    return users

def _process_tls_config(web_config):
    """Process TLS configuration from web_config."""
    if not web_config:
        return None

    tls_config = {}
    if "ClientCaCertPath" in web_config and web_config["ClientCaCertPath"]:
        tls_config["client_auth_type"] = web_config.get("ClientAuthType", "RequireAndVerifyClientCert")
        tls_config["client_ca_file"] = web_config["ClientCaCertPath"]

    if "ServerCertPath" in web_config and "ServerKeyPath" in web_config and web_config["ServerCertPath"] and web_config["ServerKeyPath"]:
        tls_config["cert_file"] = web_config["ServerCertPath"]
        tls_config["key_file"] = web_config["ServerKeyPath"]

    if not (("ServerCertPath" in web_config and web_config["ServerCertPath"]) and ("ServerKeyPath" in web_config and web_config["ServerKeyPath"])):
        print("Warning: Incomplete TLS configuration. ServerCertPath and ServerKeyPath must be specified together. Skipping TLS configuration.")

    return tls_config if tls_config else None

def _generate_config_data(json_data, config_type):
    """Generate web config data for the specified type."""
    if not json_data:
        return None

    config_key = f"{config_type}WebConfigGenerator"
    if config_key not in json_data:
        return None

    web_config = json_data[config_key]
    config_data = {}

    # Process TLS configuration
    tls_config = _process_tls_config(web_config)
    if tls_config:
        config_data["tls_server_config"] = tls_config

    # Process user authentication
    if "UserPasswordFilePath" in web_config:
        users = _read_user_passwords(web_config["UserPasswordFilePath"])
        if users:
            config_data["basic_auth_users"] = users

    return config_data if config_data else None

def generate_configs(config_file, output_dir):
    """Generate web configuration YAML files."""
    try:
        with open(config_file, "r") as f:
            json_data = json.load(f)
    except FileNotFoundError:
        print(f"Error: Config file not found: {config_file}")
        return False
    except json.JSONDecodeError:
        print(f"Error: Invalid JSON in config file: {config_file}")
        return False

    try:
        os.makedirs(output_dir, exist_ok=True)
    except OSError as e:
        print(f"Error creating output directory: {e}")
        return False

    # Generate Prometheus config
    prometheus_config = _generate_config_data(json_data, "prometheus")

    # Generate Alertmanager config
    alertmanager_config = _generate_config_data(json_data, "alertmanager")

    # Write config files - create blank files if configs are None
    try:
        with open(os.path.join(output_dir, "web-config-prom.yaml"), "w") as f:
            if prometheus_config:
                yaml.dump(prometheus_config, f)
        with open(os.path.join(output_dir, "web-config-am.yaml"), "w") as f:
            if alertmanager_config:
                yaml.dump(alertmanager_config, f)
    except (OSError, yaml.YAMLError) as e:
        print(f"Error writing config files: {e}")
        return False

    return True

def main() -> None:
    """
    Main entry point for the script.
    """
    if len(sys.argv) != 3:
        print("Usage: python generate_web_config_yaml.py <config_file_path> <output_directory>")
        sys.exit(1)

    config_file = sys.argv[1]
    output_dir = sys.argv[2]

    if not config_file or not output_dir:
        print("Error: Both input config file path and output directory are required.")
        sys.exit(1)

    configs_generated = generate_configs(config_file, output_dir)

    if configs_generated:
        print(f"Successfully generated configurations in directory: {output_dir}")
    else:
        print("Configuration generation failed.")
        sys.exit(1)

if __name__ == '__main__':
    main()
