# This file was generated by liblab | https://liblab.com/

from typing import List
from .utils.validator import Validator
from .utils.base_service import BaseService
from ..net.transport.serializer import Serializer
from ..models.worker_documents_by_id_container import WorkerDocumentsByIdContainer
from ..models.utils.cast_models import cast_models
from ..models.sort_dir_enum import SortDirEnum
from ..models.response_estimate_first_payment_container import (
    ResponseEstimateFirstPaymentContainer,
)
from ..models.input_to_patch_contract_external_id import InputToPatchContractExternalId
from ..models.get_contract_list_currencies import GetContractListCurrencies
from ..models.generic_result_updated import GenericResultUpdated
from ..models.generic_result_deleted import GenericResultDeleted
from ..models.generic_result_created import GenericResultCreated
from ..models.final_payment_calculated_container import FinalPaymentCalculatedContainer
from ..models.file_object import FileObject
from ..models.estimate_first_payment_container import EstimateFirstPaymentContainer
from ..models.download_worker_documents_by_id_container import (
    DownloadWorkerDocumentsByIdContainer,
)
from ..models.contracts_sort_by_enum import ContractsSortByEnum
from ..models.contract_type_enum import ContractTypeEnum
from ..models.contract_template_list_container import ContractTemplateListContainer
from ..models.contract_status_enum import ContractStatusEnum
from ..models.contract_signature_to_create_container import (
    ContractSignatureToCreateContainer,
)
from ..models.contract_list_container import ContractListContainer
from ..models.contract_invitation_to_create_container import (
    ContractInvitationToCreateContainer,
)
from ..models.contract_document_container import ContractDocumentContainer
from ..models.contract_container import ContractContainer
from ..models.calculate_final_payment_calculation_type import (
    CalculateFinalPaymentCalculationType,
)
from ..models.alternate_email_item import AlternateEmailItem


class ContractsService(BaseService):

    @cast_models
    def get_contract_list(
        self,
        after_cursor: str = None,
        limit: float = None,
        order_direction: SortDirEnum = None,
        types: List[ContractTypeEnum] = None,
        statuses: List[ContractStatusEnum] = None,
        team_id: str = None,
        external_id: str = None,
        countries: List[str] = None,
        currencies: GetContractListCurrencies = None,
        search: str = None,
        sort_by: ContractsSortByEnum = None,
    ) -> ContractListContainer:
        """Retrieve a list of contracts.

        :param after_cursor: Return next page of results after given cursor., defaults to None
        :type after_cursor: str, optional
        :param limit: Return a page of results with given number of records; NOTE technically ALL query parameters are strings or array of strings, defaults to None
        :type limit: float, optional
        :param order_direction: Order direction of results; ascending or descending., defaults to None
        :type order_direction: SortDirEnum, optional
        :param types: You can filter contracts by type, a contract is included in results if its type is in this list., defaults to None
        :type types: List[ContractTypeEnum], optional
        :param statuses: You can filter contracts by current status, a contract is included in results if its status is in this list., defaults to None
        :type statuses: List[ContractStatusEnum], optional
        :param team_id: Filter contracts for given team ID; NOTE: technically ALL query parameters are strings or array of strings, defaults to None
        :type team_id: str, optional
        :param external_id: Filter contracts for given external ID, defaults to None
        :type external_id: str, optional
        :param countries: Country codes of contracts to filter., defaults to None
        :type countries: List[str], optional
        :param currencies: Currency codes of contracts to filter., defaults to None
        :type currencies: GetContractListCurrencies, optional
        :param search: Include a contract if by name or contractor name contains given search term., defaults to None
        :type search: str, optional
        :param sort_by: Sort contracts by given field name., defaults to None
        :type sort_by: ContractsSortByEnum, optional
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: ContractListContainer
        """

        Validator(str).is_optional().validate(after_cursor)
        Validator(float).is_optional().min(1).max(99).validate(limit)
        Validator(SortDirEnum).is_optional().validate(order_direction)
        Validator(ContractTypeEnum).is_array().is_optional().validate(types)
        Validator(ContractStatusEnum).is_array().is_optional().validate(statuses)
        Validator(str).is_optional().validate(team_id)
        Validator(str).is_optional().validate(external_id)
        Validator(str).is_array().is_optional().validate(countries)
        Validator(GetContractListCurrencies).is_optional().validate(currencies)
        Validator(str).is_optional().validate(search)
        Validator(ContractsSortByEnum).is_optional().validate(sort_by)

        serialized_request = (
            Serializer(f"{self.base_url}/contracts", self.get_default_headers())
            .add_query("after_cursor", after_cursor)
            .add_query("limit", limit)
            .add_query("order_direction", order_direction)
            .add_query("types", types)
            .add_query("statuses", statuses)
            .add_query("team_id", team_id)
            .add_query("external_id", external_id)
            .add_query("countries", countries)
            .add_query("currencies", currencies)
            .add_query("search", search)
            .add_query("sort_by", sort_by)
            .serialize()
            .set_method("GET")
        )

        response = self.send_request(serialized_request)

        return ContractListContainer._unmap(response)

    @cast_models
    def get_contract_by_id(self, contract_id: str) -> ContractContainer:
        """Retrieve a single contract.

        :param contract_id: Deel contract id.
        :type contract_id: str
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: ContractContainer
        """

        Validator(str).validate(contract_id)

        serialized_request = (
            Serializer(
                f"{self.base_url}/contracts/{{contract_id}}", self.get_default_headers()
            )
            .add_path("contract_id", contract_id)
            .serialize()
            .set_method("GET")
        )

        response = self.send_request(serialized_request)

        return ContractContainer._unmap(response)

    @cast_models
    def attach_external_id(
        self, request_body: InputToPatchContractExternalId, contract_id: str
    ) -> GenericResultCreated:
        """Add an external Id to a Deel contract. You can use this to add a Deel contract's refernece Id in your platform. External Id can be passed as a query parameter in List contract endpoint to find this conract later.

        :param request_body: The request body.
        :type request_body: InputToPatchContractExternalId
        :param contract_id: Deel contract id.
        :type contract_id: str
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: GenericResultCreated
        """

        Validator(InputToPatchContractExternalId).validate(request_body)
        Validator(str).validate(contract_id)

        serialized_request = (
            Serializer(
                f"{self.base_url}/contracts/{{contract_id}}", self.get_default_headers()
            )
            .add_path("contract_id", contract_id)
            .serialize()
            .set_method("PATCH")
            .set_body(request_body)
        )

        response = self.send_request(serialized_request)

        return GenericResultCreated._unmap(response)

    @cast_models
    def add_contract_document(
        self, contract_id: str, request_body: dict = None
    ) -> ContractDocumentContainer:
        """Attach a file to contract document.

        :param request_body: The request body., defaults to None
        :type request_body: dict, optional
        :param contract_id: Deel contract id.
        :type contract_id: str
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: ContractDocumentContainer
        """

        Validator(dict).is_optional().validate(request_body)
        Validator(str).validate(contract_id)

        serialized_request = (
            Serializer(
                f"{self.base_url}/contracts/{{contract_id}}/documents",
                self.get_default_headers(),
            )
            .add_path("contract_id", contract_id)
            .serialize()
            .set_method("POST")
            .set_body(request_body, "multipart/form-data")
        )

        response = self.send_request(serialized_request)

        return ContractDocumentContainer._unmap(response)

    @cast_models
    def edit_contract_document(
        self, contract_id: str, request_body: dict = None
    ) -> ContractDocumentContainer:
        """Overwrite the file currently attached to contract document.

        :param request_body: The request body., defaults to None
        :type request_body: dict, optional
        :param contract_id: Deel contract id.
        :type contract_id: str
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: ContractDocumentContainer
        """

        Validator(dict).is_optional().validate(request_body)
        Validator(str).validate(contract_id)

        serialized_request = (
            Serializer(
                f"{self.base_url}/contracts/{{contract_id}}/documents",
                self.get_default_headers(),
            )
            .add_path("contract_id", contract_id)
            .serialize()
            .set_method("PUT")
            .set_body(request_body, "multipart/form-data")
        )

        response = self.send_request(serialized_request)

        return ContractDocumentContainer._unmap(response)

    @cast_models
    def get_alternate_emails_by_contract_id(
        self, contract_id: str
    ) -> List[AlternateEmailItem]:
        """Returns an array of alternate email objects

        :param contract_id: Deel contract id.
        :type contract_id: str
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: List[AlternateEmailItem]
        """

        Validator(str).validate(contract_id)

        serialized_request = (
            Serializer(
                f"{self.base_url}/contracts/{{contract_id}}/alternate_emails",
                self.get_default_headers(),
            )
            .add_path("contract_id", contract_id)
            .serialize()
            .set_method("GET")
        )

        response = self.send_request(serialized_request)

        return [AlternateEmailItem._unmap(item) for item in response]

    @cast_models
    def sign_contract(
        self, request_body: ContractSignatureToCreateContainer, contract_id: str
    ) -> GenericResultCreated:
        """Sign a contract as a client.

        :param request_body: The request body.
        :type request_body: ContractSignatureToCreateContainer
        :param contract_id: Deel contract id.
        :type contract_id: str
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: GenericResultCreated
        """

        Validator(ContractSignatureToCreateContainer).validate(request_body)
        Validator(str).validate(contract_id)

        serialized_request = (
            Serializer(
                f"{self.base_url}/contracts/{{contract_id}}/signatures",
                self.get_default_headers(),
            )
            .add_path("contract_id", contract_id)
            .serialize()
            .set_method("POST")
            .set_body(request_body)
        )

        response = self.send_request(serialized_request)

        return GenericResultCreated._unmap(response)

    @cast_models
    def archive_contract(self, contract_id: str) -> GenericResultUpdated:
        """Archive a terminated, cancelled or completed contract.

        :param contract_id: Deel contract id.
        :type contract_id: str
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: GenericResultUpdated
        """

        Validator(str).validate(contract_id)

        serialized_request = (
            Serializer(
                f"{self.base_url}/contracts/{{contract_id}}/archive",
                self.get_default_headers(),
            )
            .add_path("contract_id", contract_id)
            .serialize()
            .set_method("PATCH")
        )

        response = self.send_request(serialized_request)

        return GenericResultUpdated._unmap(response)

    @cast_models
    def invite_to_sign_contract(
        self, request_body: ContractInvitationToCreateContainer, contract_id: str
    ) -> GenericResultCreated:
        """Invite a worker to sign the contract. Worker will be notified via email.

        :param request_body: The request body.
        :type request_body: ContractInvitationToCreateContainer
        :param contract_id: Deel contract id.
        :type contract_id: str
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: GenericResultCreated
        """

        Validator(ContractInvitationToCreateContainer).validate(request_body)
        Validator(str).validate(contract_id)

        serialized_request = (
            Serializer(
                f"{self.base_url}/contracts/{{contract_id}}/invitations",
                self.get_default_headers(),
            )
            .add_path("contract_id", contract_id)
            .serialize()
            .set_method("POST")
            .set_body(request_body)
        )

        response = self.send_request(serialized_request)

        return GenericResultCreated._unmap(response)

    @cast_models
    def uninvite_to_sign_contract(self, contract_id: str) -> GenericResultDeleted:
        """Remove invite in order to re-invite a worker to sign the contract.

        :param contract_id: Deel contract id.
        :type contract_id: str
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: GenericResultDeleted
        """

        Validator(str).validate(contract_id)

        serialized_request = (
            Serializer(
                f"{self.base_url}/contracts/{{contract_id}}/invitations",
                self.get_default_headers(),
            )
            .add_path("contract_id", contract_id)
            .serialize()
            .set_method("DELETE")
        )

        response = self.send_request(serialized_request)

        return GenericResultDeleted._unmap(response)

    @cast_models
    def calculate_final_payment(
        self,
        contract_id: str,
        end_date: str = None,
        calculation_type: CalculateFinalPaymentCalculationType = None,
        workweek_start: str = None,
        workweek_end: str = None,
    ) -> FinalPaymentCalculatedContainer:
        """Calculate the final payment due to the contractor when ending the contract.

        :param contract_id: Deel contract id.
        :type contract_id: str
        :param end_date: The day to end the contract., defaults to None
        :type end_date: str, optional
        :param calculation_type: The days to calculate., defaults to None
        :type calculation_type: CalculateFinalPaymentCalculationType, optional
        :param workweek_start: The day the work week starts, 0 to 6, defaults to None
        :type workweek_start: str, optional
        :param workweek_end: The day the work week ends, 0 to 6, defaults to None
        :type workweek_end: str, optional
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: FinalPaymentCalculatedContainer
        """

        Validator(str).validate(contract_id)
        Validator(str).is_optional().pattern("^\d{4}-\d{2}-\d{2}$").validate(end_date)
        Validator(CalculateFinalPaymentCalculationType).is_optional().validate(
            calculation_type
        )
        Validator(str).is_optional().validate(workweek_start)
        Validator(str).is_optional().validate(workweek_end)

        serialized_request = (
            Serializer(
                f"{self.base_url}/contracts/{{contract_id}}/final-payments",
                self.get_default_headers(),
            )
            .add_path("contract_id", contract_id)
            .add_query("end_date", end_date, nullable=True)
            .add_query("calculation_type", calculation_type)
            .add_query("workweek_start", workweek_start)
            .add_query("workweek_end", workweek_end)
            .serialize()
            .set_method("GET")
        )

        response = self.send_request(serialized_request)

        return FinalPaymentCalculatedContainer._unmap(response)

    @cast_models
    def post_contract_estimate(
        self, request_body: EstimateFirstPaymentContainer
    ) -> ResponseEstimateFirstPaymentContainer:
        """First payment is calculated from the number of working/calendar days between their start date and the start of the payment cycle.

        :param request_body: The request body.
        :type request_body: EstimateFirstPaymentContainer
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: ResponseEstimateFirstPaymentContainer
        """

        Validator(EstimateFirstPaymentContainer).validate(request_body)

        serialized_request = (
            Serializer(
                f"{self.base_url}/contracts/estimate", self.get_default_headers()
            )
            .serialize()
            .set_method("POST")
            .set_body(request_body)
        )

        response = self.send_request(serialized_request)

        return ResponseEstimateFirstPaymentContainer._unmap(response)

    @cast_models
    def get_contract_templates(self) -> ContractTemplateListContainer:
        """Retrieve a list of contract templates in your organization.

        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: ContractTemplateListContainer
        """

        serialized_request = (
            Serializer(
                f"{self.base_url}/contract-templates", self.get_default_headers()
            )
            .serialize()
            .set_method("GET")
        )

        response = self.send_request(serialized_request)

        return ContractTemplateListContainer._unmap(response)

    @cast_models
    def get_worker_documents_by_id(
        self, worker_id: str
    ) -> WorkerDocumentsByIdContainer:
        """Retrieve a list of documents of a worker.

        :param worker_id: Unique identifier for a worker.
        :type worker_id: str
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: successful operation
        :rtype: WorkerDocumentsByIdContainer
        """

        Validator(str).validate(worker_id)

        serialized_request = (
            Serializer(
                f"{self.base_url}/workers/{{worker_id}}/documents",
                self.get_default_headers(),
            )
            .add_path("worker_id", worker_id)
            .serialize()
            .set_method("GET")
        )

        response = self.send_request(serialized_request)

        return WorkerDocumentsByIdContainer._unmap(response)

    @cast_models
    def get_download_worker_documents_by_id(
        self, worker_id: str, document_id: float
    ) -> DownloadWorkerDocumentsByIdContainer:
        """Get the download link of worker document.

        :param worker_id: Unique identifier for a worker.
        :type worker_id: str
        :param document_id: Unique identifier for a compliance document in Deel.
        :type document_id: float
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: successful operation
        :rtype: DownloadWorkerDocumentsByIdContainer
        """

        Validator(str).validate(worker_id)
        Validator(float).validate(document_id)

        serialized_request = (
            Serializer(
                f"{self.base_url}/workers/{{worker_id}}/documents/{{document_id}}/download",
                self.get_default_headers(),
            )
            .add_path("worker_id", worker_id)
            .add_path("document_id", document_id)
            .serialize()
            .set_method("GET")
        )

        response = self.send_request(serialized_request)

        return DownloadWorkerDocumentsByIdContainer._unmap(response)
