# Copyright: (c) 2024, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)

"""Service module utilities."""

from __future__ import annotations

import copy
from dataclasses import replace
from typing import Any, Callable

from ansible_collections.snailed.ez_compose.plugins.module_utils.common import (
    State,
    recursive_update,
    run_module,
    update_project,
)

BASE_SERVICE_ARGS = {
    "project_name": {
        "type": "str",
        "required": True,
    },
    "name": {
        "type": "str",
        "required": True,
    },
    "image": {
        "type": "str",
    },
    "defaults": {
        "type": "dict",
    },
}


def apply_base(state: State) -> State:
    """Apply base service configuration."""
    service_name = state.module.params["name"]
    project_name = state.module.params["project_name"]
    image = state.module.params["image"]

    new: dict[str, Any] = {
        "service_name": f"{project_name}_{service_name}",
        "hostname": f"{project_name}_{service_name}",
        "image": image,
        "restart": "unless-stopped",
        "environment": {},
        "labels": {},
        "volumes": [],
        "networks": {
            f"{project_name}_internal": None,
        },
    }

    return update(state, new)


def set_defaults(state: State) -> State:
    """Set default values for a service."""
    container_name = state.module.params["name"]
    defaults = state.module.params["defaults"]
    project = copy.deepcopy(state.after)
    services = project["services"]
    service = services[container_name]

    _ = recursive_update(service, defaults)

    services.update({container_name: service})

    return replace(state, after=project)


def update(state: State, update: dict[str, Any]) -> State:
    """Update a service with the given dictionary."""
    project = copy.deepcopy(state.after)
    service_name = state.module.params["name"]

    _ = recursive_update(project["services"][service_name], update)

    return replace(state, after=project)


def run(
    extra_args: dict[str, Any] | None = None,
    helper: Callable[[State], State] = lambda _: _,
) -> None:
    """Wrap module execution function for service helpers."""
    def execute(state: State) -> State:
        for f in [apply_base, set_defaults, helper, update_project]:
            state = f(state)
        return state

    run_module({**BASE_SERVICE_ARGS, **(extra_args or {})}, execute)