# Copyright (C) 2023 Cochise Ruhulessin
#
# All rights reserved. No warranty, explicit or implicit, provided. In
# no event shall the author(s) be liable for any claim or damages.
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import inspect
from collections import OrderedDict
from typing import get_origin
from typing import Any
from typing import Annotated

import fastapi
import fastapi.params

from canonical.ext.resource import IResourceRepository
from .resourceapplication import ResourceApplication
from .resourceclient import ResourceClient
from .resourcerouter import ResourceRouter


__all__: list[str] = [
    'ResourceApplication',
    'ResourceClient',
    'ResourceRouter'
]

def setup_dependencies(
    repository: type[IResourceRepository]
):
    async def f(
        request: fastapi.Request,
        resources: IResourceRepository = fastapi.Depends(repository)
    ):
        setattr(request.state, 'resources', resources)

    return [fastapi.Depends(f)]


def inject(*args: Any, **kwargs: Any):
    def f(request: fastapi.Request, **kwargs: Any):
        for k, v in kwargs.items():
            setattr(request.state, k, v)

    sig = inspect.signature(f)
    params: OrderedDict[str, inspect.Parameter] = OrderedDict([
        ('request', sig.parameters['request'])
    ])
    for i, dependency in enumerate(args):
        name = f'__arg_{i}'
        if isinstance(dependency, fastapi.params.Depends):
            kwargs[name] = dependency
            continue
        if not get_origin(dependency) == Annotated:
            continue
        params[name] = inspect.Parameter(
            kind=inspect.Parameter.POSITIONAL_ONLY,
            name=name,
            annotation=dependency
        )
        
    for name, dependency in kwargs.items():
        params[name] = inspect.Parameter(
            kind=inspect.Parameter.KEYWORD_ONLY,
            name=name,
            default=dependency,
            annotation=Any
        )
    setattr(f, '__signature__', sig.replace(parameters=list(params.values())))
    return fastapi.Depends(f)