# Copyright 2025 Softwell S.r.l.
# Licensed under the Apache License, Version 2.0

"""GenropyAsgiServer — AsgiServer with GenroPy site and database integration.

Reads a single GenroPy instance from config and mounts it at the root
via server.wsgi_app. ASGI apps coexist on reserved paths.

Usage (config.yaml):
    server:
      host: "0.0.0.0"
      port: 8080

    genropy:
      instance: "test_invoice_pg"
      debug: true

    databases:
      default:
        genropy_app: "sourcerer"

Usage (Python):
    from genropy_asgi import GenropyAsgiServer
    server = GenropyAsgiServer(server_dir=".")
    server.run()
"""

from __future__ import annotations

import atexit
import logging
import os
from pathlib import Path
from types import SimpleNamespace
from typing import Any

from genro_asgi import AsgiServer

log = logging.getLogger("genropy_asgi")


class GenropyAsgiServer(AsgiServer):
    """AsgiServer with a GenroPy site at root and optional database connections.

    Reads 'genropy' section from config.yaml for the site instance.
    Reads 'databases' section for GenroPy database connections.

    Attributes:
        gnr_apps: Dict of GnrApp instances keyed by database name.
    """

    __slots__ = ("gnr_apps",)

    def __init__(
        self,
        server_dir: str | Path | None = None,
        host: str | None = None,
        port: int | None = None,
        reload: bool | None = None,
        argv: list[str] | None = None,
        parent: Any = None,
    ) -> None:
        super().__init__(
            server_dir=server_dir,
            host=host,
            port=port,
            reload=reload,
            argv=argv,
            parent=parent,
        )
        self.gnr_apps: dict[str, Any] = {}
        self._load_databases()
        self._load_genropy_site()

    def _load_genropy_site(self) -> None:
        """Create GnrWsgiSite from genropy config and set as wsgi_app."""
        genropy_config = self.config["genropy"]
        if not genropy_config:
            return

        if hasattr(genropy_config, "as_dict"):
            genropy_config = genropy_config.as_dict()

        instance = genropy_config.get("instance")
        if not instance:
            return

        debug = genropy_config.get("debug", True)
        noclean = genropy_config.get("noclean", False)

        from gnr.core.gnrconfig import getGnrConfig
        from gnr.app.pathresolver import PathResolver
        from gnr.web.gnrwsgisite import GnrWsgiSite

        gnr_config = getGnrConfig(set_environment=True)
        site_path = PathResolver().site_name_to_path(instance)
        script_path = os.path.join(site_path, "root.py")

        options = SimpleNamespace(
            debug=debug,
            noclean=noclean,
            reload=False,
            remote_edit=None,
            source_instance=None,
            restore=None,
        )

        log.info("Creating GnrWsgiSite for instance '%s'", instance)
        site = GnrWsgiSite(
            script_path,
            site_name=instance,
            _gnrconfig=gnr_config,
            options=options,
        )
        site._local_mode = True
        atexit.register(site.on_site_stop)
        self.wsgi_app = site
        log.info("GenroPy instance '%s' mounted at root", instance)

    def _load_databases(self) -> None:
        """Read databases section from config and create connections."""
        databases = self.config["databases"]
        if not databases:
            return

        if hasattr(databases, "as_dict"):
            databases = databases.as_dict()

        for name, db_config in databases.items():
            if isinstance(db_config, str):
                db_config = {"uri": db_config}

            genropy_app_name = db_config.get("genropy_app")
            if genropy_app_name:
                self._create_genropy_db(name, genropy_app_name)

    def _create_genropy_db(self, name: str, app_name: str) -> None:
        """Create a GnrApp and register its db connection."""
        from gnr.app.gnrapp import GnrApp

        log.info("Creating GnrApp '%s' for database '%s'", app_name, name)
        gnr_app = GnrApp(app_name)
        self.gnr_apps[name] = gnr_app
        self.register_db(name, gnr_app.db)
        log.info("Database '%s' registered from GnrApp '%s'", name, app_name)


if __name__ == "__main__":
    server = GenropyAsgiServer()
    server.run()
