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

# FIX: This entire library is broken and needs to be fixed

from __future__ import annotations

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

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

if TYPE_CHECKING:
    from ansible_collections.snailed.ez_compose.plugins.module_utils.models import (
        State,
    )

BASE_ARGS: dict[str, Any] = {
    "name": {"type": "str"},
    "overwrite": {"type": "dict"},
}


def apply_base(state: State, params: dict[str, Any]) -> State:
    project_name: str = state.module.params["name"]

    new: dict[str, Any] = {
        "container_name": f"{project_name}_{params['name']}",
        "hostname": f"{project_name}_{params['name']}",
        "restart": "unless-stopped",
        "environment": {},
        "labels": {},
        "volumes": [],
        "networks": {
            "internal": None,
        },
    } | (
        state.module.params.get("settings", {})
        .get("default_definition", {})
        .get(params["name"], {})
    )

    return update(state, params, new)


def apply_definition(state: State, params: dict[str, Any], definition: dict[str, Any]) -> State:
    project = copy.deepcopy(state.after)
    services: dict[str, Any] = project["services"]
    service: dict[str, Any] = services[params["name"]]

    service = recursive_update(service, definition)

    return update(state, params, service)


def apply_settings(state: State, params: dict[str, Any]) -> State:
    settings = state.module.params.get("settings", {})
    params = settings.get("service_default_args", {}).get(params["name"], {}) | params

    return update(
        state,
        params,
        settings.get("service_default_definitions", {}).get(params["name"], {}),
    )


def update(state: State, params: dict[str, Any], update: dict[str, Any]) -> State:
    project = copy.deepcopy(state.after)

    project["services"][params["name"]] = recursive_update(
        project["services"].get(params["name"], {}),
        update,
    )

    new_definition = project["services"][params["name"]]
    new_volumes: list[dict[str, Any]] = new_definition.get("volumes") or []

    # FIX: this silently throws out misconfigured volumes
    unique_volumes = list({vol["source"]: vol for vol in new_volumes if "target" in vol}.values())

    project["services"][params["name"]]["volumes"] = unique_volumes

    return replace(state, after=project)


def run_helper(
    state: State,
    params: dict[str, Any],
    helper: Callable[[State, dict[str, Any]], State] = lambda x, _: x,
) -> State:
    if not params.get("name"):
        params["name"] = str.split(helper.__module__, ".")[-1]

    if not (overwrite := params.get("overwrite")):
        overwrite = params.get("definition", {})

    state = apply_base(state, params)
    state = apply_settings(state, params)
    state = helper(state, params)
    state = apply_definition(state, params, overwrite)
    return update_project(state)