from __future__ import annotations

import json
import os
from typing import Dict

from .engine import AzurePolicyEngine


def _read_body(path: str) -> Dict:
    with open(path, "r", encoding="utf-8") as f:
        return json.load(f)


def _print(obj: object) -> None:
    print(json.dumps(obj, indent=2))


# Handler implementations (small, focused)
def _handle_list(args, engine: AzurePolicyEngine) -> None:
    _print(engine.list_policies())


def _handle_get(args, engine: AzurePolicyEngine) -> None:
    _print(engine.get_policy(args.name))


def _handle_deploy(args, engine: AzurePolicyEngine) -> None:
    body = _read_body(args.file)
    _print(engine.deploy_policy(args.name, body))


def _handle_list_assignments(args, engine: AzurePolicyEngine) -> None:
    _print(engine.list_assignments())


def _handle_create_assignment(args, engine: AzurePolicyEngine) -> None:
    common_scope = args.scope or (
        f"/providers/Microsoft.Management/managementGroups/{getattr(args, 'mgmt_group', None)}"
        if getattr(args, "mgmt_group", None)
        else None
    )
    body = _read_body(args.file)
    if getattr(args, "dry_run", False):
        _print(
            {
                "dry_run": True,
                "action": "create_assignment",
                **engine.prepare_assignment_payload(
                    args.name, body, scope=common_scope
                ),
            }
        )
    else:
        _print(engine.create_assignment(args.name, body, scope=common_scope))


def _handle_update_assignment(args, engine: AzurePolicyEngine) -> None:
    common_scope = args.scope or (
        f"/providers/Microsoft.Management/managementGroups/{getattr(args, 'mgmt_group', None)}"
        if getattr(args, "mgmt_group", None)
        else None
    )
    body = _read_body(args.file)
    if getattr(args, "dry_run", False):
        _print(
            {
                "dry_run": True,
                "action": "update_assignment",
                **engine.prepare_assignment_payload(
                    args.name, body, scope=common_scope
                ),
            }
        )
    else:
        _print(engine.update_assignment(args.name, body, scope=common_scope))


def _handle_delete_assignment(args, engine: AzurePolicyEngine) -> None:
    common_scope = args.scope or (
        f"/providers/Microsoft.Management/managementGroups/{getattr(args, 'mgmt_group', None)}"
        if getattr(args, "mgmt_group", None)
        else None
    )
    if getattr(args, "dry_run", False):
        _print(
            {
                "dry_run": True,
                "action": "delete_assignment",
                "scope": common_scope,
                "name": args.name,
            }
        )
    else:
        _print(engine.delete_assignment(args.name, scope=common_scope))


def _handle_add_assignment(args, engine: AzurePolicyEngine) -> None:
    if args.backend != "file":
        import sys

        print("add-assignment only supported for file backend", file=sys.stderr)
        sys.exit(2)
    body = _read_body(args.file)
    dest = os.path.join(engine.assignments_dir, f"{args.name}.json")
    with open(dest, "w", encoding="utf-8") as f:
        json.dump(body, f, indent=2)
    _print({"file": dest, "status": "written"})


def _handle_list_initiatives(args, engine: AzurePolicyEngine) -> None:
    res = engine.list_initiatives()
    if getattr(args, "raw", False):
        _print(res)
    else:
        print("Initiatives:")
        for it in res:
            print(" - ", it.get("name"))


def _handle_assign_initiative(args, engine: AzurePolicyEngine) -> None:
    common_scope = args.scope or (
        f"/providers/Microsoft.Management/managementGroups/{getattr(args, 'mgmt_group', None)}"
        if getattr(args, "mgmt_group", None)
        else None
    )
    body = _read_body(args.file)
    if getattr(args, "dry_run", False):
        _print(
            {
                "dry_run": True,
                "action": "assign_initiative",
                "initiative": args.initiative_name,
                **engine.prepare_assignment_payload(
                    args.assignment_name, body, scope=common_scope
                ),
            }
        )
    else:
        _print(
            engine.assign_initiative(
                args.initiative_name, args.assignment_name, body, scope=common_scope
            )
        )


# Dispatch map keeps handle_command small and easy to extend
_DISPATCH = {
    "list": _handle_list,
    "get": _handle_get,
    "deploy": _handle_deploy,
    "assignments": _handle_list_assignments,
    "create-assignment": _handle_create_assignment,
    "update-assignment": _handle_update_assignment,
    "delete-assignment": _handle_delete_assignment,
    "add-assignment": _handle_add_assignment,
    "list-initiatives": _handle_list_initiatives,
    "assign-initiative": _handle_assign_initiative,
}


def handle_command(args, engine: AzurePolicyEngine) -> None:
    """Dispatch and perform the requested command. This module keeps CLI main small and testable."""
    cmd = getattr(args, "cmd", None)
    handler = _DISPATCH.get(cmd)
    if handler:
        handler(args, engine)
    else:
        # unknown command -> print help-ish information
        print("unknown command or handler not implemented")
