#!/usr/bin/python
# Copyright: (c) 2025, Luca Bilke <luca@bil.ke>
# MIT License (see LICENSE)
# ruff: noqa: E402

from __future__ import annotations

DOCUMENTATION = """
---
module: compose
version_added: 1.0.0
short_description: Simplify docker-compose deployments.
description: Easily create docker-compose files using a single module
seealso:
    - name: Compose file reference
      description: Complete reference of the compose file spec.
      link: https://docs.docker.com/reference/compose-file/
attributes:
    check_mode:
        support: full
    diff_mode:
        support: full
options:
    name:
        description:
            - Name of the compose project to create or modify.
        aliases: [project]
        type: str
    project_dir:
        description:
            - Path to store project directory under.
        type: path
    settings:
        description:
            - Settings/Defaults for the module.
        type: dict
        suboptions:
            external_networks:
                description:
                    - Networks to mark as external.
                type: list
                elements: str
            external_volumes:
                description:
                    - Volumes to mark as external.
                type: list
                elements: str
            default_definition:
                description:
                    - Default definition for all containers.
                    - Overwritten by per-service defaults.
                type: dict
            service_default_definitions:
                description:
                    - Default definitions for each service
                type: dict
                suboptions:
                    custom:
                        description:
                            - Default definitions for custom services.
                        type: dict
                    docker_in_docker:
                        description:
                            - Default definitions for docker_in_docker services.
                        type: dict
                    docker_socket_proxy:
                        description:
                            - Default definitions for docker_socket_proxy services.
                        type: dict
                    docker_volume_backupper:
                        description:
                            - Default definitions for docker_volume_backupper services.
                        type: dict
                    mariadb:
                        description:
                            - Default definitions for mariadb services.
                        type: dict
                    postgres:
                        description:
                            - Default definitions for postgres services.
                        type: dict
                    redis:
                        description:
                            - Default definitions for redis services.
                        type: dict
            service_default_args:
                description:
                    - Default arguments for each service helper.
                type: dict
                suboptions:
                    custom:
                        description:
                            - Configuration for custom service.
                        type: list
                        elements: dict
                        suboptions:
                            name:
                                description:
                                    - Name of the service
                                type: str
                            definition:
                                description:
                                    - Service definition
                                type: dict
                            label_helpers:
                                description:
                                    - Label helper configurations
                                type: dict
                                suboptions:
                                    docker_volume_backupper:
                                        description:
                                            - Configuration for docker_volume_backupper labels.
                                        type: list
                                        elements: dict
                                        suboptions:
                                            stop:
                                                description:
                                                    - If true, stop the container when backing up.
                                                type: bool
                                    homepage:
                                        description:
                                            - Configuration for homepage labels.
                                        type: list
                                        elements: dict
                                        suboptions:
                                            name:
                                                description:
                                                    - Name to set on dashboard.
                                                    - Defaults to name of service.
                                                type: str
                                            href:
                                                description:
                                                    - HREF to set on dashboard.
                                                type: str
                                            icon:
                                                description:
                                                    - URL to an image to use as icon.
                                                type: str
                                            description:
                                                description:
                                                    - Description text to set on dashboard.
                                                type: str
                                            group:
                                                description:
                                                    - Group to place service under on dashboard.
                                                type: str
                                            widget:
                                                description:
                                                    - Widget configuration.
                                                    - See U(https://gethomepage.dev/configs/services/) for more info.
                                                type: dict
                                    traefik_middleware:
                                        description:
                                            - Configuration for traefik_middleware labels.
                                        type: list
                                        elements: dict
                                        suboptions:
                                            name:
                                                description:
                                                    - Name of the middleware.
                                                type: string
                                            middleware:
                                                description:
                                                    - The name of the traefik middleware to use.
                                                type: str
                                            proxy_type:
                                                description:
                                                    - Traefik proxy type.
                                                type: str
                                                choices: [http, tcp, udp]
                                            settings:
                                                description:
                                                    - Middleware options.
                                                type: dict
                                    traefik_router:
                                        description:
                                            - Configuration for traefik_router labels.
                                        type: list
                                        elements: dict
                                        suboptions:
                                            name:
                                                description:
                                                    - Name of the middleware.
                                                type: string
                                            rule:
                                                description:
                                                    - Routing rule to match.
                                                type: str
                                            proxy_type:
                                                description:
                                                    - Traefik proxy type.
                                                type: str
                                                choices: [http, tcp, udp]
                                            service:
                                                description:
                                                    - Traefik service to point at.
                                                type: str
                                            certresolver:
                                                description:
                                                    - Certresolver to use.
                                                type: str
                                            entrypoints:
                                                description:
                                                    - Entrypoints to listen on.
                                                type: list
                                                elements: str
                                            middlewares:
                                                description:
                                                    - Middlewares to use.
                                                type: list
                                                elements: str
                                    traefik_service:
                                        description:
                                            - Configuration for traefik_service labels.
                                        type: list
                                        elements: dict
                                        suboptions:
                                            name:
                                                description:
                                                    - Name of the middleware.
                                                type: string
                                            proxy_type:
                                                description:
                                                    - Traefik proxy type.
                                                type: str
                                                choices: [http, tcp, udp]
                                            port:
                                                description:
                                                    - Port to forward to.
                                                type: int
                                            protocol_version:
                                                description:
                                                    - Proxy protocol version to use (TCP only).
                                                type: int
                    docker_in_docker:
                        description:
                            - Configuration for docker_in_docker service.
                        type: list
                        elements: dict
                        suboptions:
                            name:
                                description:
                                    - Name of the service.
                                type: str
                            overwrite:
                                description:
                                    - Definition to force.
                                type: dict
                    docker_socket_proxy:
                        description:
                            - Configuration for docker_socket_proxy service.
                        type: list
                        elements: dict
                        suboptions:
                            read_only:
                                description:
                                    - If true, only allow read access to the docker socket.
                                type: bool
                            name:
                                description:
                                    - Name of the service.
                                type: str
                            overwrite:
                                description:
                                    - Definition to force.
                                type: dict
                    docker_volume_backupper:
                        description:
                            - Configuration for docker_volume_backupper service.
                        type: list
                        elements: dict
                        suboptions:
                            archive:
                                description:
                                    - Directory to store backups in.
                                type: path
                            backup_volumes:
                                description:
                                    - List of volume names of volumes to backup.
                                type: list
                                elements: str
                            docker_socket_proxy:
                                description:
                                    - Hostname of a docker socket proxy to use.
                                type: str
                            name:
                                description:
                                    - Name of the service.
                                type: str
                            overwrite:
                                description:
                                    - Definition to force.
                                type: dict
                    mariadb:
                        description:
                            - Configuration for mariadb service.
                        type: list
                        elements: dict
                        suboptions:
                            backup:
                                description:
                                    - If true, add labels for the docker volume backupper.
                                type: bool
                            database:
                                description:
                                    - Name of database.
                                type: str
                            username:
                                description:
                                    - Username for database.
                                type: str
                            password:
                                description:
                                    - Password for database.
                                type: str
                            root_password:
                                description:
                                    - Root password for database.
                                type: str
                            name:
                                description:
                                    - Name of the service.
                                type: str
                            overwrite:
                                description:
                                    - Definition to force.
                                type: dict
                    postgres:
                        description:
                            - Configuration for postgres service.
                        type: list
                        elements: dict
                        suboptions:
                            backup:
                                description:
                                    - If true, add labels for the docker volume backupper.
                                type: bool
                            database:
                                description:
                                    - Name of database.
                                type: str
                            username:
                                description:
                                    - Username for database.
                                type: str
                            password:
                                description:
                                    - Password for database.
                                type: str
                            name:
                                description:
                                    - Name of the service.
                                type: str
                            overwrite:
                                description:
                                    - Definition to force.
                                type: dict
                    redis:
                        description:
                            - Configuration for redis service.
                        type: list
                        elements: dict
                        suboptions:
                            name:
                                description:
                                    - Name of the service.
                                type: str
                            overwrite:
                                description:
                                    - Definition to force.
                                type: dict
            label_default_args:
                description:
                    - Default arguments for each label helper.
                type: dict
                suboptions:
                    docker_volume_backupper:
                        description:
                            - Configuration for docker_volume_backupper labels.
                        type: list
                        elements: dict
                        suboptions:
                            stop:
                                description:
                                    - If true, stop the container when backing up.
                                type: bool
                    homepage:
                        description:
                            - Configuration for homepage labels.
                        type: list
                        elements: dict
                        suboptions:
                            name:
                                description:
                                    - Name to set on dashboard.
                                    - Defaults to name of service.
                                type: str
                            href:
                                description:
                                    - HREF to set on dashboard.
                                type: str
                            icon:
                                description:
                                    - URL to an image to use as icon.
                                type: str
                            description:
                                description:
                                    - Description text to set on dashboard.
                                type: str
                            group:
                                description:
                                    - Group to place service under on dashboard.
                                type: str
                            widget:
                                description:
                                    - Widget configuration.
                                    - See U(https://gethomepage.dev/configs/services/) for more info.
                                type: dict
                    traefik_middleware:
                        description:
                            - Configuration for traefik_middleware labels.
                        type: list
                        elements: dict
                        suboptions:
                            name:
                                description:
                                    - Name of the middleware.
                                type: string
                            middleware:
                                description:
                                    - The name of the traefik middleware to use.
                                type: str
                            proxy_type:
                                description:
                                    - Traefik proxy type.
                                type: str
                                choices: [http, tcp, udp]
                            settings:
                                description:
                                    - Middleware options.
                                type: dict
                    traefik_router:
                        description:
                            - Configuration for traefik_router labels.
                        type: list
                        elements: dict
                        suboptions:
                            name:
                                description:
                                    - Name of the middleware.
                                type: string
                            rule:
                                description:
                                    - Routing rule to match.
                                type: str
                            proxy_type:
                                description:
                                    - Traefik proxy type.
                                type: str
                                choices: [http, tcp, udp]
                            service:
                                description:
                                    - Traefik service to point at.
                                type: str
                            certresolver:
                                description:
                                    - Certresolver to use.
                                type: str
                            entrypoints:
                                description:
                                    - Entrypoints to listen on.
                                type: list
                                elements: str
                            middlewares:
                                description:
                                    - Middlewares to use.
                                type: list
                                elements: str
                    traefik_service:
                        description:
                            - Configuration for traefik_service labels.
                        type: list
                        elements: dict
                        suboptions:
                            name:
                                description:
                                    - Name of the middleware.
                                type: string
                            proxy_type:
                                description:
                                    - Traefik proxy type.
                                type: str
                                choices: [http, tcp, udp]
                            port:
                                description:
                                    - Port to forward to.
                                type: int
                            protocol_version:
                                description:
                                    - Proxy protocol version to use (TCP only).
                                type: int
    services:
        description:
            - Services to create in the project.
        type: dict
        suboptions:
            custom:
                description:
                    - Configuration for custom service.
                type: list
                elements: dict
                suboptions:
                    name:
                        description:
                            - Name of the service
                        type: str
                        required: true
                    definition:
                        description:
                            - Service definition
                        type: dict
                        required: true
                    label_helpers:
                        description:
                            - Label helper configurations
                        type: dict
                        suboptions:
                            docker_volume_backupper:
                                description:
                                    - Configuration for docker_volume_backupper labels.
                                type: list
                                elements: dict
                                suboptions:
                                    stop:
                                        description:
                                            - If true, stop the container when backing up.
                                        type: bool
                            homepage:
                                description:
                                    - Configuration for homepage labels.
                                type: list
                                elements: dict
                                suboptions:
                                    name:
                                        description:
                                            - Name to set on dashboard.
                                            - Defaults to name of service.
                                        type: str
                                    href:
                                        description:
                                            - HREF to set on dashboard.
                                        type: str
                                    icon:
                                        description:
                                            - URL to an image to use as icon.
                                        type: str
                                    description:
                                        description:
                                            - Description text to set on dashboard.
                                        type: str
                                    group:
                                        description:
                                            - Group to place service under on dashboard.
                                        type: str
                                    widget:
                                        description:
                                            - Widget configuration.
                                            - See U(https://gethomepage.dev/configs/services/) for more info.
                                        type: dict
                            traefik_middleware:
                                description:
                                    - Configuration for traefik_middleware labels.
                                type: list
                                elements: dict
                                suboptions:
                                    name:
                                        description:
                                            - Name of the middleware.
                                        type: string
                                    middleware:
                                        description:
                                            - The name of the traefik middleware to use.
                                        type: str
                                    proxy_type:
                                        description:
                                            - Traefik proxy type.
                                        type: str
                                        choices: [http, tcp, udp]
                                    settings:
                                        description:
                                            - Middleware options.
                                        type: dict
                            traefik_router:
                                description:
                                    - Configuration for traefik_router labels.
                                type: list
                                elements: dict
                                suboptions:
                                    name:
                                        description:
                                            - Name of the middleware.
                                        type: string
                                    rule:
                                        description:
                                            - Routing rule to match.
                                        type: str
                                    proxy_type:
                                        description:
                                            - Traefik proxy type.
                                        type: str
                                        choices: [http, tcp, udp]
                                    service:
                                        description:
                                            - Traefik service to point at.
                                        type: str
                                    certresolver:
                                        description:
                                            - Certresolver to use.
                                        type: str
                                    entrypoints:
                                        description:
                                            - Entrypoints to listen on.
                                        type: list
                                        elements: str
                                    middlewares:
                                        description:
                                            - Middlewares to use.
                                        type: list
                                        elements: str
                            traefik_service:
                                description:
                                    - Configuration for traefik_service labels.
                                type: list
                                elements: dict
                                suboptions:
                                    name:
                                        description:
                                            - Name of the middleware.
                                        type: string
                                    proxy_type:
                                        description:
                                            - Traefik proxy type.
                                        type: str
                                        choices: [http, tcp, udp]
                                    port:
                                        description:
                                            - Port to forward to.
                                        type: int
                                    protocol_version:
                                        description:
                                            - Proxy protocol version to use (TCP only).
                                        type: int
            docker_in_docker:
                description:
                    - Configuration for docker_in_docker service.
                type: list
                elements: dict
                suboptions:
                    name:
                        description:
                            - Name of the service.
                        type: str
                    overwrite:
                        description:
                            - Definition to force.
                        type: dict
            docker_socket_proxy:
                description:
                    - Configuration for docker_socket_proxy service.
                type: list
                elements: dict
                suboptions:
                    read_only:
                        description:
                            - If true, only allow read access to the docker socket.
                        type: bool
                        required: true
                    name:
                        description:
                            - Name of the service.
                        type: str
                    overwrite:
                        description:
                            - Definition to force.
                        type: dict
            docker_volume_backupper:
                description:
                    - Configuration for docker_volume_backupper service.
                type: list
                elements: dict
                suboptions:
                    archive:
                        description:
                            - Directory to store backups in.
                        type: path
                    backup_volumes:
                        description:
                            - List of volume names of volumes to backup.
                        type: list
                        elements: str
                        required: true
                    docker_socket_proxy:
                        description:
                            - Hostname of a docker socket proxy to use.
                        type: str
                    name:
                        description:
                            - Name of the service.
                        type: str
                    overwrite:
                        description:
                            - Definition to force.
                        type: dict
            mariadb:
                description:
                    - Configuration for mariadb service.
                type: list
                elements: dict
                suboptions:
                    backup:
                        description:
                            - If true, add labels for the docker volume backupper.
                        type: bool
                        default: true
                    database:
                        description:
                            - Name of database.
                        type: str
                        required: true
                    username:
                        description:
                            - Username for database.
                        type: str
                        required: true
                    password:
                        description:
                            - Password for database.
                        type: str
                        required: true
                    root_password:
                        description:
                            - Root password for database.
                        type: str
                    name:
                        description:
                            - Name of the service.
                        type: str
                    overwrite:
                        description:
                            - Definition to force.
                        type: dict
            postgres:
                description:
                    - Configuration for postgres service.
                type: list
                elements: dict
                suboptions:
                    backup:
                        description:
                            - If true, add labels for the docker volume backupper.
                        type: bool
                        default: true
                    database:
                        description:
                            - Name of database.
                        type: str
                        required: true
                    username:
                        description:
                            - Username for database.
                        type: str
                        required: true
                    password:
                        description:
                            - Password for database.
                        type: str
                        required: true
                    name:
                        description:
                            - Name of the service.
                        type: str
                    overwrite:
                        description:
                            - Definition to force.
                        type: dict
            redis:
                description:
                    - Configuration for redis service.
                type: list
                elements: dict
                suboptions:
                    name:
                        description:
                            - Name of the service.
                        type: str
                    overwrite:
                        description:
                            - Definition to force.
                        type: dict
"""  # noqa: E501

from dataclasses import asdict
from importlib.util import find_spec

from ansible.module_utils.basic import AnsibleModule  # pyright: ignore[reportMissingTypeStubs]
from ansible_collections.snailed.ez_docker.plugins.module_utils import (
    common,
    service,
    spec,
)


def main() -> None:
    module = AnsibleModule(
        argument_spec={
            "name": {
                "aliases": ["project"],
                "type": "str",
                "required": True,
            },
            "project_dir": {
                "type": "path",
                "default": "/var/lib/ez_docker",
            },
            "settings": spec.settings_spec(),
            "services": spec.service_argument_spec(),
        },
        supports_check_mode=True,
    )

    if not find_spec("yaml"):
        module.fail_json("PyYAML needs to be installed on the host to use this plugin")  # pyright: ignore[reportUnknownMemberType]

    try:
        state = common.get_state(module)
    except Exception as e:  # noqa: BLE001
        module.fail_json(f"Error while reading existing compose file: {e}")  # pyright: ignore[reportUnknownMemberType]

    for name, services_params in state.params.get("services", {}).items():
        for index, service_params in enumerate(services_params):
            default_params = service.common.get_default_args(state, name)
            params = common.recursive_update(default_params, service_params)
            params["_index"] = index
            helper = getattr(service, name).helper
            state = service.common.run_helper(state, params, helper)

    state = common.update_project(state)
    state = common.set_result(state)

    if state.result.changed and not module.check_mode:
        try:
            state = common.write_compose(state)
        except Exception as e:  # noqa: BLE001
            module.fail_json(f"Error while writing new compose file: {e}")  # pyright: ignore[reportUnknownMemberType]

    ret = asdict(state.result)

    module.exit_json(**ret)  # pyright: ignore[reportUnknownMemberType]


if __name__ == "__main__":
    main()