from typing import Dict
from typing import Optional

from furl import Path as UrlPath
from furl.furl import furl as Url
from requests.models import Response
from testlodge._types import Identifier
from testlodge.api.base import BaseAPI
from testlodge.models.project import ProjectJSON
from testlodge.models.project import ProjectListJSON


class ProjectAPI(BaseAPI):
    """API for projects.

    Endpoints
    ---------
    * List
    * Show
    * Create
    * Update
    * Delete
    """

    name: str = 'project'

    def _list(
        self,
        page: int = 1,
    ) -> ProjectListJSON:
        """Paginated list of all projects for a user.

        Parameters
        ----------
        page: int, default=1
            Default: 1
            Page to return.
        """

        method: str = 'GET'
        url: Url = self.client.base_url / UrlPath('/projects.json')
        if page != 1:
            params = {'page': page}
        else:
            params = {}

        response: Response = self.client._request(
            method=method, url=url, params=params
        )
        project_list: ProjectListJSON = response.json()

        return project_list

    def _show(
        self,
        project_id: int,
    ) -> ProjectJSON:
        """Get the details for a project.

        Parameters
        ----------
        project_id: Identifier
            The ID of the project.
        """

        method = 'GET'
        url: Url = self.client.base_url / UrlPath(
            f'/projects/{project_id}.json'
        )

        response: Response = self.client._request(
            method=method,
            url=url,
        )
        project_json: ProjectJSON = response.json()

        return project_json

    def _create(
        self,
        name: str,
        description: Optional[str] = None,
        issue_tracker_credential_id: Optional[int] = None,
        issue_tracker_project_id: Optional[str] = None,
    ) -> ProjectJSON:
        """Create a project.

        Parameters
        ----------
        name: str
            Name of the project.
        description: str, optional
            Project description.
        issue_tracker_credential_id: int, optional
            ID for an integrated issue tracker.
        issue_tracker_project_id: str, optional
            Project ID associated with integrated issue tracker.
        """

        method = 'POST'
        url: Url = self.client.base_url / UrlPath('/projects.json')

        data: dict = dict(name=name)
        if description is not None:
            data['description'] = description
        if issue_tracker_credential_id is not None:
            data['issue_tracker_credential_id'] = str(
                issue_tracker_credential_id
            )
        if issue_tracker_project_id is not None:
            data['issue_tracker_project_id'] = issue_tracker_project_id

        response: Response = self.client._request(
            method=method, url=url, json=data
        )
        project_json: ProjectJSON = response.json()

        return project_json

    def _update(
        self,
        project_id: int,
        project: ProjectJSON,
    ) -> ProjectJSON:
        """Update a project.

        Parameters
        ----------
        project_id: int
            The ID of the project.
        project: ProjectJSON
            name: str
                Name of the project.
            description: str
                Project description.
            issue_tracker_credential_id: int
                ID for an integrated issue tracker.
            issue_tracker_project_id: str
                Project ID associated with integrated issue tracker.
        """

        method = 'PATCH'
        url: Url = self.client.base_url / UrlPath(
            f'/projects/{project_id}.json'
        )

        response: Response = self.client._request(
            method=method,
            url=url,
            json=project,
        )
        project_json: ProjectJSON = response.json()

        return project_json

    def _delete(
        self,
        project_id: int,
    ) -> None:
        """Delete a project.

        Parameters
        ----------
        project_id: int
            The ID of the project.
        """

        method = 'DELETE'
        url: Url = self.client.base_url / UrlPath(
            f'/projects/{project_id}.json'
        )

        response: Response = self.client._request(method=method, url=url)

        status_code: int = response.status_code
        if status_code != 204:
            print(f'Unexpected response code: {status_code}')

        return None
