"""The main entrypoint for :term:`GSO`, and the different ways in which it can be run."""

import os
from typing import Annotated

import sentry_sdk
import strawberry
import typer
from celery import Celery
from orchestrator import OrchestratorCore, app_settings
from orchestrator.cli.main import app as cli_app
from orchestrator.graphql import DEFAULT_GRAPHQL_MODELS, SCALAR_OVERRIDES
from orchestrator.services.tasks import initialise_celery
from orchestrator.settings import ExecutorType

# noinspection PyUnresolvedReferences
import gso.products
import gso.workflows  # noqa: F401
from gso.api import router as api_router
from gso.auth.oidc import oidc_instance
from gso.auth.opa import graphql_opa_instance, opa_instance
from gso.graphql_api.types import GSO_SCALAR_OVERRIDES
from gso.settings import load_oss_params
from gso.utils.types.interfaces import LAGMember

SCALAR_OVERRIDES.update(GSO_SCALAR_OVERRIDES)


def gso_initialise_celery(celery: Celery) -> None:
    """Initialise the :term:`Celery` app."""
    initialise_celery(celery)
    celery.conf.task_routes = {}


def init_gso_app() -> OrchestratorCore:
    """Initialise the :term:`GSO` app."""
    app = OrchestratorCore(base_settings=app_settings)
    app.register_authentication(oidc_instance)
    app.register_authorization(opa_instance)
    app.register_graphql_authorization(graphql_opa_instance)

    @strawberry.experimental.pydantic.type(model=LAGMember)
    class LAGMemberGraphql:
        self_reference_block: Annotated["LAGMemberGraphql", strawberry.lazy("gso.utils.types.interfaces")] | None = None
        interface_name: str
        interface_description: str

    updated_graphql_models = DEFAULT_GRAPHQL_MODELS | {
        "LAGMemberGraphql": LAGMemberGraphql,
    }

    app.register_graphql(graphql_models=updated_graphql_models)
    app.include_router(api_router, prefix="/api")

    if app_settings.EXECUTOR == ExecutorType.WORKER:
        config = load_oss_params()
        celery = Celery(
            "geant-service-orchestrator",
            broker=config.CELERY.broker_url,
            backend=config.CELERY.result_backend,
            include=["orchestrator.services.tasks"],
        )
        celery.conf.update(
            result_expires=config.CELERY.result_expires,
        )
        gso_initialise_celery(celery)

    return app


def init_cli_app() -> typer.Typer:
    """Initialise :term:`GSO` as a CLI application."""
    from gso.cli import imports, netbox  # noqa: PLC0415

    cli_app.add_typer(imports.app, name="import-cli")
    cli_app.add_typer(netbox.app, name="netbox-cli")
    return cli_app()


def init_sentry() -> None:
    """Only initialize Sentry if not in testing mode."""
    if os.getenv("TESTING", "false").lower() == "false" and (sentry_params := load_oss_params().SENTRY):
        sentry_sdk.init(
            dsn=sentry_params.DSN, environment=load_oss_params().GENERAL.environment, traces_sample_rate=1.0
        )


init_sentry()