# LocalStack Resource Provider Scaffolding v2
from __future__ import annotations

from pathlib import Path
from typing import TypedDict

from botocore.exceptions import ClientError

import localstack.services.cloudformation.provider_utils as util
from localstack.aws.api.cloudcontrol import InvalidRequestException, ResourceNotFoundException
from localstack.services.cloudformation.resource_provider import (
    OperationStatus,
    ProgressEvent,
    ResourceProvider,
    ResourceRequest,
)


class ApiGatewayResourceProperties(TypedDict):
    ParentId: str | None
    PathPart: str | None
    RestApiId: str | None
    ResourceId: str | None


REPEATED_INVOCATION = "repeated_invocation"


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

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

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

        Required properties:
          - ParentId
          - PathPart
          - RestApiId

        Create-only properties:
          - /properties/PathPart
          - /properties/ParentId
          - /properties/RestApiId

        Read-only properties:
          - /properties/ResourceId

        IAM permissions required:
          - apigateway:POST

        """
        model = request.desired_state
        apigw = request.aws_client_factory.apigateway

        params = {
            "restApiId": model.get("RestApiId"),
            "pathPart": model.get("PathPart"),
            "parentId": model.get("ParentId"),
        }
        if not params.get("parentId"):
            # get root resource id
            resources = apigw.get_resources(restApiId=params["restApiId"])["items"]
            root_resource = ([r for r in resources if r["path"] == "/"] or [None])[0]
            if not root_resource:
                raise Exception(
                    "Unable to find root resource for REST API {}".format(params["restApiId"])
                )
            params["parentId"] = root_resource["id"]
        response = apigw.create_resource(**params)

        model["ResourceId"] = response["id"]
        model["ParentId"] = response["parentId"]
        return ProgressEvent(
            status=OperationStatus.SUCCESS,
            resource_model=model,
            custom_context=request.custom_context,
        )

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

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

    def list(
        self,
        request: ResourceRequest[ApiGatewayResourceProperties],
    ) -> ProgressEvent[ApiGatewayResourceProperties]:
        if "RestApiId" not in request.desired_state:
            # TODO: parity
            raise InvalidRequestException(
                f"Missing or invalid ResourceModel property in {self.TYPE} list handler request input: 'RestApiId'"
            )

        rest_api_id = request.desired_state["RestApiId"]
        try:
            resources = request.aws_client_factory.apigateway.get_resources(restApiId=rest_api_id)[
                "items"
            ]
        except ClientError as exc:
            if exc.response.get("Error", {}).get("Code", {}) == "NotFoundException":
                raise ResourceNotFoundException(f"Invalid API identifier specified: {rest_api_id}")
            raise

        return ProgressEvent(
            status=OperationStatus.SUCCESS,
            resource_models=[
                ApiGatewayResourceProperties(
                    RestApiId=rest_api_id,
                    ResourceId=resource["id"],
                    ParentId=resource.get("parentId"),
                    PathPart=resource.get("path"),
                )
                for resource in resources
            ],
        )

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

        IAM permissions required:
          - apigateway:DELETE
        """
        model = request.desired_state
        apigw = request.aws_client_factory.apigateway

        try:
            apigw.delete_resource(restApiId=model["RestApiId"], resourceId=model["ResourceId"])
        except apigw.exceptions.NotFoundException:
            pass

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

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

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