# LocalStack Resource Provider Scaffolding v2
from __future__ import annotations

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 LambdaVersionProperties(TypedDict):
    FunctionName: str | None
    CodeSha256: str | None
    Description: str | None
    Id: str | None
    ProvisionedConcurrencyConfig: ProvisionedConcurrencyConfiguration | None
    Version: str | None


class ProvisionedConcurrencyConfiguration(TypedDict):
    ProvisionedConcurrentExecutions: int | None


REPEATED_INVOCATION = "repeated_invocation"


class LambdaVersionProvider(ResourceProvider[LambdaVersionProperties]):
    TYPE = "AWS::Lambda::Version"  # Autogenerated. Don't change
    SCHEMA = util.get_schema_path(Path(__file__))  # Autogenerated. Don't change

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

        Primary identifier fields:
          - /properties/Id

        Required properties:
          - FunctionName

        Create-only properties:
          - /properties/FunctionName

        Read-only properties:
          - /properties/Id
          - /properties/Version



        """
        model = request.desired_state
        lambda_client = request.aws_client_factory.lambda_
        ctx = request.custom_context

        params = util.select_attributes(model, ["FunctionName", "CodeSha256", "Description"])

        if not ctx.get(REPEATED_INVOCATION):
            response = lambda_client.publish_version(**params)
            model["Version"] = response["Version"]
            model["Id"] = response["FunctionArn"]
            if model.get("ProvisionedConcurrencyConfig"):
                lambda_client.put_provisioned_concurrency_config(
                    FunctionName=model["FunctionName"],
                    Qualifier=model["Version"],
                    ProvisionedConcurrentExecutions=model["ProvisionedConcurrencyConfig"][
                        "ProvisionedConcurrentExecutions"
                    ],
                )
            ctx[REPEATED_INVOCATION] = True
            return ProgressEvent(
                status=OperationStatus.IN_PROGRESS,
                resource_model=model,
                custom_context=request.custom_context,
            )

        if model.get("ProvisionedConcurrencyConfig"):
            # Assumption: Ready provisioned concurrency implies the function version is ready
            provisioned_concurrency_config = lambda_client.get_provisioned_concurrency_config(
                FunctionName=model["FunctionName"],
                Qualifier=model["Version"],
            )
            if provisioned_concurrency_config["Status"] == "IN_PROGRESS":
                return ProgressEvent(
                    status=OperationStatus.IN_PROGRESS,
                    resource_model=model,
                    custom_context=request.custom_context,
                )
            elif provisioned_concurrency_config["Status"] == "READY":
                return ProgressEvent(
                    status=OperationStatus.SUCCESS,
                    resource_model=model,
                )
            else:
                return ProgressEvent(
                    status=OperationStatus.FAILED,
                    resource_model=model,
                    message="",
                    error_code="VersionStateFailure",  # TODO: not parity tested
                )
        else:
            version = lambda_client.get_function(FunctionName=model["Id"])
            if version["Configuration"]["State"] == "Pending":
                return ProgressEvent(
                    status=OperationStatus.IN_PROGRESS,
                    resource_model=model,
                    custom_context=request.custom_context,
                )
            elif version["Configuration"]["State"] == "Active":
                return ProgressEvent(
                    status=OperationStatus.SUCCESS,
                    resource_model=model,
                )
            else:
                return ProgressEvent(
                    status=OperationStatus.FAILED,
                    resource_model=model,
                    message="",
                    error_code="VersionStateFailure",  # TODO: not parity tested
                )

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


        """
        raise NotImplementedError

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


        """
        model = request.desired_state
        lambda_client = request.aws_client_factory.lambda_

        # without qualifier entire function is deleted instead of just version
        # provisioned concurrency is automatically deleted upon deleting a function or function version
        lambda_client.delete_function(FunctionName=model["Id"], Qualifier=model["Version"])

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

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


        """
        raise NotImplementedError
