import os
from dataclasses import asdict
from typing import IO

import httpx
from aext_panels_server.api import HeadersAndCookies, ProjectDeploymentMicroserviceAPI
from aext_panels_server.const import Environment
from aext_panels_server.request_schemas.notebook_projects_microservice import (
    CreateProject,
    CreateProjectVersion,
)
from aext_panels_server.utils import get_environment, handle_network_exceptions


class ProjectDeploymentMicroserviceAPIV2(ProjectDeploymentMicroserviceAPI):
    NUCLEUS_BASE_URLS = {
        Environment.PRODUCTION: "https://anaconda.cloud/api/panels/v2/",
        Environment.STAGING: "https://nucleus-latest.anacondaconnect.com/api/panels/v2/",
        Environment.LOCAL: os.getenv("DEV_PANELS_MICROSERVICE_ADDRESS_V2", "http://notebook-deployment-api:8000/v2/"),
    }

    def _get_headers_and_cookies(self, **kwargs) -> HeadersAndCookies:
        headers_and_cookies = super()._get_headers_and_cookies()
        headers_and_cookies.headers.update(**kwargs.pop("headers", {}))
        return headers_and_cookies

    @handle_network_exceptions(max_retries=1)
    async def create_project(self, request_data: CreateProject, archive_content: IO, **kwargs) -> httpx.Response:
        # an `app` is an updated term for v1's `project`
        # at some point, we should refactor the code to only use `app`
        endpoint = "apps/"

        data = {**asdict(request_data), "name": request_data.title}
        data.pop("title", None)
        data.pop("description", None)

        archive = {"archive": archive_content}
        return await self._post(endpoint, data=data, files=archive, **kwargs)

    @handle_network_exceptions(max_retries=1)
    async def delete_project(self, project_id: str, **kwargs) -> httpx.Response:
        # an `app` is an updated term for v1's `project`
        # at some point, we should refactor the code to only use `app`
        endpoint = f"apps/{project_id}/"
        return await self._delete(endpoint, **kwargs)

    @handle_network_exceptions(max_retries=1)
    async def download_files(self, project_id: str, project_version: str, **kwargs) -> httpx.Response:
        # an `app` is an updated term for v1's `project`
        # at some point, we should refactor the code to only use `app`
        endpoint = f"apps/{project_id}/download/{project_version}/"
        headers = {"Content-Type": "octet-stream"}  # subject to change
        return await self._get(endpoint, headers=headers, **kwargs)

    @handle_network_exceptions(max_retries=1)
    async def create_project_version(
        self, request_data: CreateProjectVersion, archive_content: IO, **kwargs
    ) -> httpx.Response:
        # an `app` is an updated term for v1's `project`
        # at some point, we should refactor the code to only use `app`
        endpoint = f"apps/{request_data.project_id}/"
        archive = {"archive": archive_content}
        return await self._post(endpoint, data=asdict(request_data), files=archive, **kwargs)

    @handle_network_exceptions(max_retries=1)
    async def get_project_notebook(self, project_id: str, version_id: str, **kwargs) -> httpx.Response:
        # an `app` is an updated term for v1's `project`
        # at some point, we should refactor the code to only use `app`
        endpoint = f"apps/{project_id}/storage/{version_id}/"
        return await self._get(endpoint, **kwargs)

    @handle_network_exceptions(max_retries=1)
    async def delete_project_version(self, project_id: str, version_id: str, **kwargs) -> httpx.Response:
        # an `app` is an updated term for v1's `project`
        # at some point, we should refactor the code to only use `app`
        endpoint = f"apps/{project_id}/version/{version_id}/"
        return await self._delete(endpoint, **kwargs)


project_deployment_ms_api_v2 = ProjectDeploymentMicroserviceAPIV2(get_environment())
