# Copyright (C) 2022 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information

import os
from typing import Any, Dict, Optional

from swh.core import config
from swh.search import get_search as get_swh_search
from swh.search.interface import SearchInterface
from swh.storage import get_storage as get_swh_storage
from swh.storage.interface import StorageInterface

graphql_cfg: Dict[str, Any] = {}
storage: Optional[StorageInterface] = None
search: Optional[SearchInterface] = None


def get_storage() -> StorageInterface:
    global storage
    if not storage:
        storage = get_swh_storage(**graphql_cfg["storage"])
    return storage


def get_search() -> SearchInterface:
    global search
    if not search:
        search = get_swh_search(**graphql_cfg["search"])
    return search


def load_and_check_config(config_path: Optional[str]) -> Dict[str, Any]:
    """Check the minimal configuration is set to run the api or raise an
       error explanation.

    Args:
        config_path: Path to the configuration file to load

    Raises:
        Error if the setup is not as expected

    Returns:
        configuration as a dict

    """
    if not config_path:
        raise EnvironmentError("Configuration file must be defined")

    if not os.path.exists(config_path):
        raise FileNotFoundError(f"Configuration file {config_path} does not exist")

    cfg = config.read(config_path)
    if "storage" not in cfg:
        raise KeyError("Missing 'storage' configuration")

    return cfg


def make_app_from_configfile():
    """Loading the configuration from a configuration file.

    SWH_CONFIG_FILENAME environment variable defines the
    configuration path to load.
    """
    from ariadne.asgi import GraphQL
    from starlette.applications import Starlette
    from starlette.middleware import Middleware
    from starlette.middleware.cors import CORSMiddleware

    from .app import schema, validation_rules
    from .errors import format_error

    global graphql_cfg

    if not graphql_cfg:
        config_path = os.environ.get("SWH_CONFIG_FILENAME")
        graphql_cfg = load_and_check_config(config_path)

    middleware = [
        Middleware(
            CORSMiddleware,
            # FIXME, restrict origins after deploying the JS client
            allow_origins=["*"],
            allow_methods=("GET", "POST", "OPTIONS"),
        ),
    ]

    application = Starlette(middleware=middleware)
    application.mount(
        "/",
        GraphQL(
            schema,
            debug=graphql_cfg["debug"],
            introspection=graphql_cfg["introspection"],
            validation_rules=validation_rules,
            error_formatter=format_error,
        ),
    )
    return application
