from typing import Optional, List, Dict

from thestage.config.business.config_provider import ConfigProvider
from thestage.global_dto.enums.order_direction_type import OrderDirectionType
from thestage.project.dto.delete_project_request import DeleteProjectRequest
from thestage.project.dto.delete_project_response import DeleteProjectResponse
from thestage.project.dto.list_project_request import ProjectListRequest
from thestage.project.dto.list_project_response import ProjectListResponse, ProjectBusinessStatusMapperResponse
from thestage.project.dto.modify_project_instance_assignment_request import ModifyProjectInstanceAssignmentRequest
from thestage.project.dto.modify_project_instance_assignment_response import ModifyProjectInstanceAssignmentResponse
from thestage.services.clients.thestage_api.core.api_client_core import TheStageApiClientCore

from thestage.project.dto.project_response import ProjectDto, ProjectViewResponse
from thestage.project.dto.get_deploy_ssh_key_request import ProjectGetDeploySshKeyRequest
from thestage.project.dto.get_deploy_ssh_key_response import ProjectGetDeploySshKeyResponse
from thestage.services.clients.thestage_api.dtos.entity_filter_request import EntityFilterRequest
from thestage.services.clients.thestage_api.dtos.paginated_entity_list import PaginatedEntityList


class ProjectApiClient(TheStageApiClientCore):
    def __init__(self, config_provider: ConfigProvider):
        super().__init__(url=config_provider.get_config().main.thestage_api_url)
        self.__config_provider = config_provider

    def get_project(self, slug: Optional[str], public_id: Optional[str], default_container_public_id: Optional[str]) -> Optional[ProjectViewResponse]:
        data = {
            "projectSlug": slug,
            "projectPublicId": public_id,
            "defaultContainerPublicId": default_container_public_id
        }

        response = self._request(
            method='POST',
            url='/user-api/v2/project/view',
            data=data,
            token=self.__config_provider.get_config().main.thestage_auth_token,
        )

        result = ProjectViewResponse.model_validate(response) if response else None
        return result if result and result.isSuccess else None

    def get_project_deploy_ssh_key(self, public_id: str) -> str:
        request = ProjectGetDeploySshKeyRequest(
            projectPublicId=public_id,
        )

        response = self._request(
            method='POST',
            url='/user-api/v1/project/get-deploy-ssh-key',
            data=request.model_dump(),
            token=self.__config_provider.get_config().main.thestage_auth_token,
        )

        result = ProjectGetDeploySshKeyResponse.model_validate(response) if response else None
        return result.privateKey if result and result.isSuccess else None

    def get_project_list(
            self,
            page: int = 1,
            limit: int = 10,
            statuses: List[str] = None,
            rented_instance_public_id: Optional[str] = None,
            rented_instance_slug: Optional[str] = None,
            self_hosted_instance_public_id: Optional[str] = None,
            self_hosted_instance_slug: Optional[str] = None,
    ) -> PaginatedEntityList[ProjectDto]:
        request = ProjectListRequest(
            statuses=statuses,
            rentedInstancePublicId=rented_instance_public_id,
            rentedInstanceSlug=rented_instance_slug,
            selfHostedInstancePublicId=self_hosted_instance_public_id,
            selfHostedInstanceSlug=self_hosted_instance_slug,
            entityFilterRequest=EntityFilterRequest(
                orderByField="createdAt",
                orderByDirection=OrderDirectionType.DESC,
                page=page,
                limit=limit,
            ),
        )

        response = self._request(
            method='POST',
            url='/user-api/v1/project/list',
            data=request.model_dump(),
            token=self.__config_provider.get_config().main.thestage_auth_token,
        )

        result = ProjectListResponse.model_validate(response) if response else None
        return result.paginatedList if result and result.isSuccess else None


    def get_project_business_status_map(self) -> Optional[Dict[str, str]]:
        response = self._request(
            method='POST',
            url='/user-api/v1/project/status-localized-map',
            data=None,
            token=self.__config_provider.get_config().main.thestage_auth_token,
        )

        data = ProjectBusinessStatusMapperResponse.model_validate(response) if response else None
        return data.project_business_status_map if data else None


    def modify_project_instance_assignment(
            self,
            project_public_id,
            project_slug,
            rented_instance_public_id_to_assign,
            rented_instance_slug_to_assign,
            rented_instance_public_id_to_delete,
            rented_instance_slug_to_delete,
            self_hosted_instance_public_id_to_assign,
            self_hosted_instance_slug_to_assign,
            self_hosted_instance_public_id_to_delete,
            self_hosted_instance_slug_to_delete) -> Optional[ModifyProjectInstanceAssignmentResponse]:

        request = ModifyProjectInstanceAssignmentRequest(
            projectPublicId=project_public_id,
            projectSlug=project_slug,
            instanceRentedPublicIdsToAssign=rented_instance_public_id_to_assign,
            instanceRentedSlugsToAssign=rented_instance_slug_to_assign,
            instanceRentedPublicIdsToDelete=rented_instance_public_id_to_delete,
            instanceRentedSlugsToDelete=rented_instance_slug_to_delete,
            selfhostedInstancePublicIdsToAssign=self_hosted_instance_public_id_to_assign,
            selfhostedInstanceSlugsToAssign=self_hosted_instance_slug_to_assign,
            selfhostedInstancePublicIdsToDelete=self_hosted_instance_public_id_to_delete,
            selfhostedInstanceSlugsToDelete=self_hosted_instance_slug_to_delete,
        )

        response = self._request(
            method='POST',
            url='/user-api/v1/project/modify-instance-assignment',
            data=request.model_dump(),
            token=self.__config_provider.get_config().main.thestage_auth_token,
        )

        return ModifyProjectInstanceAssignmentResponse.model_validate(response) if response else None


    def delete_project(self, project_public_id, project_slug) -> Optional[DeleteProjectResponse]:
        request = DeleteProjectRequest(
            projectPublicId=project_public_id,
            projectSlug=project_slug,
        )

        response = self._request(
            method='POST',
            url='/user-api/v1/project/delete',
            data=request.model_dump(),
            token=self.__config_provider.get_config().main.thestage_auth_token,
        )

        return DeleteProjectResponse.model_validate(response) if response else None
