# LocalStack Resource Provider Scaffolding v2
from __future__ import annotations

from copy import deepcopy
from pathlib import Path
from typing import TypedDict

import localstack.services.cloudformation.provider_utils as util
from localstack.services.cloudformation.resource_provider import (
    OperationStatus,
    ProgressEvent,
    ResourceProvider,
    ResourceRequest,
)


class ApiGatewayMethodProperties(TypedDict):
    HttpMethod: str | None
    ResourceId: str | None
    RestApiId: str | None
    ApiKeyRequired: bool | None
    AuthorizationScopes: list[str] | None
    AuthorizationType: str | None
    AuthorizerId: str | None
    Integration: Integration | None
    MethodResponses: list[MethodResponse] | None
    OperationName: str | None
    RequestModels: dict | None
    RequestParameters: dict | None
    RequestValidatorId: str | None


class IntegrationResponse(TypedDict):
    StatusCode: str | None
    ContentHandling: str | None
    ResponseParameters: dict | None
    ResponseTemplates: dict | None
    SelectionPattern: str | None


class Integration(TypedDict):
    Type: str | None
    CacheKeyParameters: list[str] | None
    CacheNamespace: str | None
    ConnectionId: str | None
    ConnectionType: str | None
    ContentHandling: str | None
    Credentials: str | None
    IntegrationHttpMethod: str | None
    IntegrationResponses: list[IntegrationResponse] | None
    PassthroughBehavior: str | None
    RequestParameters: dict | None
    RequestTemplates: dict | None
    TimeoutInMillis: int | None
    Uri: str | None


class MethodResponse(TypedDict):
    StatusCode: str | None
    ResponseModels: dict | None
    ResponseParameters: dict | None


REPEATED_INVOCATION = "repeated_invocation"


class ApiGatewayMethodProvider(ResourceProvider[ApiGatewayMethodProperties]):
    TYPE = "AWS::ApiGateway::Method"  # Autogenerated. Don't change
    SCHEMA = util.get_schema_path(Path(__file__))  # Autogenerated. Don't change

    def create(
        self,
        request: ResourceRequest[ApiGatewayMethodProperties],
    ) -> ProgressEvent[ApiGatewayMethodProperties]:
        """
        Create a new resource.

        Primary identifier fields:
          - /properties/RestApiId
          - /properties/ResourceId
          - /properties/HttpMethod

        Required properties:
          - RestApiId
          - ResourceId
          - HttpMethod

        Create-only properties:
          - /properties/RestApiId
          - /properties/ResourceId
          - /properties/HttpMethod



        IAM permissions required:
          - apigateway:PUT
          - apigateway:GET

        """
        model = request.desired_state
        apigw = request.aws_client_factory.apigateway
        operation_model = apigw.meta.service_model.operation_model

        apigw.put_method(
            **util.convert_request_kwargs(model, operation_model("PutMethod").input_shape)
        )

        # setting up integrations
        integration = model.get("Integration")
        if integration:
            apigw.put_integration(
                restApiId=model.get("RestApiId"),
                resourceId=model.get("ResourceId"),
                httpMethod=model.get("HttpMethod"),
                **util.convert_request_kwargs(
                    integration, operation_model("PutIntegration").input_shape
                ),
            )

            integration_responses = integration.pop("IntegrationResponses", [])
            for integration_response in integration_responses:
                apigw.put_integration_response(
                    restApiId=model.get("RestApiId"),
                    resourceId=model.get("ResourceId"),
                    httpMethod=model.get("HttpMethod"),
                    **util.convert_request_kwargs(
                        integration_response, operation_model("PutIntegrationResponse").input_shape
                    ),
                )

        responses = model.get("MethodResponses", [])
        for response in responses:
            apigw.put_method_response(
                restApiId=model.get("RestApiId"),
                resourceId=model.get("ResourceId"),
                httpMethod=model.get("HttpMethod"),
                **util.convert_request_kwargs(
                    response, operation_model("PutMethodResponse").input_shape
                ),
            )

        return ProgressEvent(
            status=OperationStatus.SUCCESS,
            resource_model=model,
            custom_context=request.custom_context,
        )

    def read(
        self,
        request: ResourceRequest[ApiGatewayMethodProperties],
    ) -> ProgressEvent[ApiGatewayMethodProperties]:
        """
        Fetch resource information

        IAM permissions required:
          - apigateway:GET
        """
        raise NotImplementedError

    def delete(
        self,
        request: ResourceRequest[ApiGatewayMethodProperties],
    ) -> ProgressEvent[ApiGatewayMethodProperties]:
        """
        Delete a resource

        IAM permissions required:
          - apigateway:DELETE
        """

        # FIXME we sometimes get warnings when calling this method, probably because
        #  restAPI or resource has been already deleted
        model = request.desired_state
        apigw = request.aws_client_factory.apigateway

        try:
            apigw.delete_method(
                **util.convert_request_kwargs(
                    model, apigw.meta.service_model.operation_model("DeleteMethod").input_shape
                )
            )
        except apigw.exceptions.NotFoundException:
            pass

        return ProgressEvent(
            status=OperationStatus.SUCCESS,
            resource_model=model,
            custom_context=request.custom_context,
        )

    def update(
        self,
        request: ResourceRequest[ApiGatewayMethodProperties],
    ) -> ProgressEvent[ApiGatewayMethodProperties]:
        """
        Update a resource

        IAM permissions required:
          - apigateway:GET
          - apigateway:DELETE
          - apigateway:PUT
        """
        model = request.desired_state
        apigw = request.aws_client_factory.apigateway
        operation_model = apigw.meta.service_model.operation_model

        must_params = util.select_attributes(
            model,
            [
                "RestApiId",
                "ResourceId",
                "HttpMethod",
            ],
        )

        if integration := deepcopy(model.get("Integration")):
            integration.update(must_params)
            apigw.put_integration(
                **util.convert_request_kwargs(
                    integration, operation_model("PutIntegration").input_shape
                )
            )

        else:
            must_params.update({"AuthorizationType": model.get("AuthorizationType")})
            apigw.put_method(
                **util.convert_request_kwargs(must_params, operation_model("PutMethod").input_shape)
            )

        return ProgressEvent(
            status=OperationStatus.SUCCESS,
            resource_model=model,
            custom_context=request.custom_context,
        )
