#!/usr/bin/env python

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

from __future__ import annotations

SERVICE_BASE_DOCS = """
                type: dict
                suboptions:
                    name:
                        description:
                            - Name of the service.
                        type: str
                    image:
                        description:
                            - Image to use for service.
                        type: str
                    defaults:
                        description:
                            - Service definition to be overwritten.
                        type: dict
                    overwrite:
                        description:
                            - Service definition to overwrite with.
                        type: dict
"""

LABEL_BASE_DOCS = """
                                type: dict
                                suboptions:
"""

DOCUMENTATION = f"""
---
module: compose
short_description: Simplify docker-compose deployments
description:
    - Easily create docker-compose files using a single module
author:
    - "Luca Bilke (@ssnailed)"
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
    services:
        description:
            - Services to create in the project.
        type: list
        elements: dict
        suboptions:
            custom:
                description:
                    - Custom service definition.
{SERVICE_BASE_DOCS}
                    internal_network:
                        description:
                            - If true, add internal network to service.
                        type: bool
                        default: false
                    label_helpers:
                        description:
                            - Label helper configurations.
                        type: dict
                        suboptions:
                            docker_volume_backupper:
                                description:
                                    - Docker Volume Backupper label helper configuration.
{LABEL_BASE_DOCS}
                                    stop:
                                        description:
                                            - If true, stop the container when backing up.
                                        type: bool
                                        default: true
                            traefik_middleware:
                                description:
                                    - Traefik Middleware label helper configuration.
{LABEL_BASE_DOCS}
                                    proxy_type:
                                        description:
                                            - Traefik proxy type.
                                        type: str
                                        choices: [http, tcp, udp]
                                        default: http
                                    name:
                                        description:
                                            - Name of the middleware.
                                            - Default is generated dynamically like so:
                                            - [project_name]_[service_name]_[proxy_type]_[middleware]
                                        type: string
                                    middleware:
                                        description:
                                            - The traefik middleware to use.
                                        type: str
                                        required: true
                                    settings:
                                        description:
                                            - Middleware options.
                                        type: dict
                                        required: true
                            traefik_router:
                                description:
                                    - Traefik Router label helper configuration.
{LABEL_BASE_DOCS}
                                    proxy_type:
                                        description:
                                            - Traefik proxy type.
                                        type: str
                                        choices: [http, tcp, udp]
                                        default: http
                                    name:
                                        description:
                                            - Name of the middleware.
                                            - Default is generated dynamically like so:
                                            - [project_name]_[service_name]_[proxy_type]
                                        type: string
                                    rule:
                                        description:
                                            - Routing rule to match.
                                        type: str
                                        required: true
                                    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:
                                    - Traefik Service label helper configuration.
{LABEL_BASE_DOCS}
                                    proxy_type:
                                        description:
                                            - Traefik proxy type.
                                        type: str
                                        choices: [http, tcp, udp]
                                        default: http
                                    name:
                                        description:
                                            - Name of the middleware.
                                            - Default is generated dynamically like so:
                                            - [project_name]_[service_name]_[proxy_type]
                                        type: string
                                    port:
                                        description:
                                            - Port to forward to.
                                        type: int
            docker_in_docker:
                description:
                    - Docker-in-Docker service definition.
{SERVICE_BASE_DOCS}
            docker_socket_proxy:
                description:
                    - Docker Socket Proxy service definition.
{SERVICE_BASE_DOCS}
                    read_only:
                        description:
                            - If true, only allow read access to the docker socket.
                        type: bool
                        default: true
            docker_volume_backupper:
                description:
                    - Docker Socket Proxy service definition.
{SERVICE_BASE_DOCS}
                    archive:
                        description:
                            - Directory to store backups in.
                        type: path
                    backup_volumes:
                        description:
                            - List of volume names of volumes to backup.
                        type: list
                        elements: str
            mariadb:
                description:
                    - MariaDB service definition.
{SERVICE_BASE_DOCS}
                    backup:
                        description:
                            - If true, add labels for the docker volume backupper.
                        type: bool
                    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
            postgres:
                description:
                    - PostgreSQL service definition.
{SERVICE_BASE_DOCS}
                    backup:
                        description:
                            - If true, add labels for the docker volume backupper.
                        type: bool
                    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
            redis:
                description:
                    - Redis service definition.
{SERVICE_BASE_DOCS}
"""  # noqa: E501

from typing import Any

from ansible.module_utils.basic import AnsibleModule  # type: ignore[reportMissingStubFile]
from ansible_collections.ssnailed.ez_compose.plugins.module_utils import (
    common,
    label,
    service,
)


def label_argument_spec() -> dict[str, Any]:
    label_args: dict[str, Any] = {
        "type": "dict",
        "options": {},
    }

    for module in label.__all__:
        if module == "common":
            continue

        options = {
            **label.common.BASE_ARGS,
            **getattr(label, module).EXTRA_ARGS,
        }

        label_args["options"][module] = {
            "type": "dict",
            "options": options,
        }

    return label_args


def service_argument_spec() -> dict[str, Any]:
    service_args: dict[str, Any] = {
        "type": "dict",
        "options": {},
        "required": True,
    }

    for module in service.__all__:
        if module == "common":
            continue

        options = {
            **service.common.BASE_ARGS,
            **getattr(service, module).EXTRA_ARGS,
        }

        if module == "custom":
            options["label_helpers"] = label_argument_spec()

        service_args["options"][module] = {
            "type": "list",
            "elements": "dict",
            "options": options,
        }

    return service_args


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

    state = common.get_state(module)

    for name, args in module.params["services"].items():
        state = getattr(service, name).helper(state, args)


if __name__ == "__main__":
    main()