#!/usr/bin/env python3
import json
import argparse
import sys
import os

# Default paths
DEFAULT_POLICIES_FILE = "/usr/share/vitalinux/navegadores-web/vx-chromium-chrome-conf/vx-chromium-chrome-policies.json"
# DEFAULT_POLICIES_FILE = "/home/arturo/Dropbox/IES/vitalinux/scripts/paquetes-labels/paquetes-lubuntu/vx-dga-l-chromium-chrome-firefox-policies-conf.gitlab/usr/share/vitalinux/navegadores-web/vx-chromium-chrome-conf/vx-chromium-chrome-policies.json"
DEFAULT_OUTPUT = "/usr/share/vitalinux/navegadores-web/vx-chromium-chrome-conf/vx-chromium-chrome-conf.json"

def load_policies(policies_file):
    if not os.path.exists(policies_file):
        return {}
    try:
        with open(policies_file, 'r', encoding='utf-8') as f:
            return json.load(f)
    except Exception as e:
        print(f"Error loading policies file: {e}", file=sys.stderr)
        return {}

def show_custom_help(policies, policies_file):
    print("Uso: vx-chromium-chrome-conf-setter [opciones]")
    print("\nOpciones:")
    print("  -d, --directive DIRECTIVA  Nombre de la directiva/policy a aplicar (requiere -v)")
    print("  -v, --value VALOR          Valor de la directiva (se intenta parsear como JSON: bool, int, lista...)")
    print("  -j, --json JSON_RAW        Contenido JSON directo a aplicar")
    print("  -l, --label ETIQUETA...    Nombre de una o varias secciones predefinidas en las políticas ubicadas por defecto en /usr/share/vitalinux/navegadores-web/vx-chromium-chrome-conf/vx-chromium-chrome-policies.json, pero personalizable mediante -p")
    print("  -f, --files RUTA1 RUTA2..  Ruta de uno o varios archivos JSON con contenidos de políticas")
    print("  -p, --policies-file RUTA   Ruta del fichero de políticas de etiquetas a usar (por defecto: /usr/share/vitalinux/navegadores-web/vx-chromium-chrome-conf/vx-chromium-chrome-policies.json)")
    print("  -o, --output RUTA          Ruta absoluta del archivo de salida (por defecto: /usr/share/vitalinux/navegadores-web/vx-chromium-chrome-conf/vx-chromium-chrome-conf.json)")
    print("  -m, --modify               Modifica/Sobrescribe las directivas si ya existen")
    print("  -h, --help                 Muestra este mensaje de ayuda")
    
    if policies:
        print("\nEtiquetas (-l) disponibles en:")
        print(f"  {policies_file}")
        for key, value in policies.items():
            if key not in ["desc", "descext"]:
                desc = value.get("desc", "Sin descripción")
                print(f"  * {key:40} : {desc}")

def main():
    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument("-d", "--directive")
    parser.add_argument("-v", "--value")
    parser.add_argument("-j", "--json")
    parser.add_argument("-l", "--label", nargs="+")
    parser.add_argument("-f", "--files", nargs="+")
    parser.add_argument("-p", "--policies-file", default=DEFAULT_POLICIES_FILE)
    parser.add_argument("-o", "--output", default=DEFAULT_OUTPUT)
    parser.add_argument("-m", "--modify", action="store_true")
    parser.add_argument("-h", "--help", action="store_true")

    args = parser.parse_args()

    policies = load_policies(args.policies_file)

    if args.help:
        show_custom_help(policies, args.policies_file)
        sys.exit(0)

    if not (args.label or args.files or args.json or args.directive):
        print("Error: Debe especificar una etiqueta (-l), un JSON (-j), archivos (-f) o una directiva (-d -v).", file=sys.stderr)
        show_custom_help(policies, args.policies_file)
        sys.exit(1)

    # Collect all policies to apply
    config_to_apply = {}
    original_config_keys = set()

    # Si ya existe el archivo de salida configurado, leemos sus directivas base
    if os.path.exists(args.output):
        try:
            with open(args.output, 'r', encoding='utf-8') as f:
                loaded_config = json.load(f)
                if isinstance(loaded_config, dict):
                    config_to_apply = loaded_config
                    original_config_keys = set(config_to_apply.keys())
        except Exception as e:
            print(f"Aviso: No se pudo leer el archivo de salida existente {args.output}: {e}", file=sys.stderr)

    def merge_config(target, source):
        for k, v in source.items():
            if k in target:
                if args.modify:
                    target[k] = v
                else:
                    print(f"Aviso: La directiva '{k}' ya existe y se omitirá su nueva asignación. Usa -m/--modify para sobrescribir.")
            else:
                target[k] = v

    if args.label:
        for label in args.label:
            if label in policies:
                merge_config(config_to_apply, policies[label].get("configuracion", {}))
            else:
                print(f"Error: La etiqueta '{label}' no existe en el archivo de políticas.", file=sys.stderr)
                sys.exit(1)

    if args.files:
        for file_path in args.files:
            if os.path.exists(file_path):
                try:
                    with open(file_path, 'r', encoding='utf-8') as f:
                        file_config = json.load(f)
                        if isinstance(file_config, dict):
                            merge_config(config_to_apply, file_config)
                        else:
                            print(f"Aviso: El archivo {file_path} no contiene un objeto JSON válido (omitiendo).", file=sys.stderr)
                except Exception as e:
                    print(f"Error cargando archivo JSON {file_path}: {e}", file=sys.stderr)
                    sys.exit(1)
            else:
                print(f"Error: El archivo {file_path} no existe.", file=sys.stderr)
                sys.exit(1)

    if args.json:
        try:
            parsed_json = json.loads(args.json)
            if isinstance(parsed_json, dict):
                merge_config(config_to_apply, parsed_json)
        except json.JSONDecodeError as e:
            print(f"Error: El contenido JSON no es válido: {e}", file=sys.stderr)
            sys.exit(1)

    if args.directive:
        if args.value is None:
            print("Error: La opción -d requiere el uso de -v para especificar un valor.", file=sys.stderr)
            sys.exit(1)
        
        # Try to parse value as JSON (for bool, int, etc.), fallback to string
        try:
            val = json.loads(args.value)
        except json.JSONDecodeError:
            val = args.value
        
        merge_config(config_to_apply, {args.directive: val})

    # Save unfiltered configuration to a temporary file
    temp_file = "/tmp/vx-chromium-chrome-conf.pre"
    try:
        with open(temp_file, 'w', encoding='utf-8') as f:
            json.dump(config_to_apply, f, indent=4, ensure_ascii=False)
        print(f"Configuración completa (sin filtrar) guardada en: {temp_file}")
    except Exception as e:
        print(f"Aviso: No se pudo guardar el archivo temporal {temp_file}: {e}", file=sys.stderr)

    # Conflict Prevention - Verify managed policies in /etc/opt/chrome/policies/managed/
    managed_dir = "/etc/opt/chrome/policies/managed"
    existing_policies = set()
    if os.path.exists(managed_dir):
        for filename in sorted(os.listdir(managed_dir)):
            if filename.endswith(".json"):
                try:
                    with open(os.path.join(managed_dir, filename), 'r', encoding='utf-8') as f:
                        managed_config = json.load(f)
                        if isinstance(managed_config, dict):
                            existing_policies.update(managed_config.keys())
                except Exception as e:
                    print(f"Aviso: No se pudo leer el archivo de política gestionada {filename}: {e}", file=sys.stderr)

    final_config = {}
    for key, value in config_to_apply.items():
        if key in existing_policies:
            if args.modify:
                final_config[key] = value
                print(f"Aviso: La directiva '{key}' existe en {managed_dir}, pero se incluyó por el uso de --modify.")
            else:
                if key in original_config_keys:
                    final_config[key] = value
                    print(f"Aviso: La directiva '{key}' ya existe en las políticas gestionadas ({managed_dir}) y será omitida su modificación, conservando el valor existente.")
                else:
                    print(f"Aviso: La directiva '{key}' ya existe en las políticas gestionadas ({managed_dir}) y será omitida.")
        else:
            final_config[key] = value

    if not final_config:
        print("Aviso: No hay directivas a aplicar (todas están conflictivas o vacías).")
        sys.exit(0)

    # Ensure output directory exists
    output_dir = os.path.abspath(os.path.dirname(args.output))
    if not os.path.exists(output_dir):
        try:
            os.makedirs(output_dir, exist_ok=True)
        except Exception as e:
            print(f"Error creando el directorio de salida: {e}", file=sys.stderr)
            sys.exit(1)

    # Write the configuration
    try:
        with open(args.output, 'w', encoding='utf-8') as f:
            json.dump(final_config, f, indent=4, ensure_ascii=False)
        print(f"Configuración aplicada con éxito en: {args.output}")
    except Exception as e:
        print(f"Error escribiendo el archivo de configuración: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    main()
