# 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.utils.cast_models import cast_models
from ..models.invoice_adjustment_type_enum import InvoiceAdjustmentTypeEnum
from ..models.invoice_adjustment_to_update_container import (
    InvoiceAdjustmentToUpdateContainer,
)
from ..models.invoice_adjustment_to_create_container import (
    InvoiceAdjustmentToCreateContainer,
)
from ..models.invoice_adjustment_status_enum import InvoiceAdjustmentStatusEnum
from ..models.invoice_adjustment_reviews_to_create_container import (
    InvoiceAdjustmentReviewsToCreateContainer,
)
from ..models.invoice_adjustment_review_to_create_container import (
    InvoiceAdjustmentReviewToCreateContainer,
)
from ..models.invoice_adjustment_list_container import InvoiceAdjustmentListContainer
from ..models.invoice_adjustment_created_container import (
    InvoiceAdjustmentCreatedContainer,
)
from ..models.invoice_adjustment_attachment_container import (
    InvoiceAdjustmentAttachmentContainer,
)
from ..models.generic_result_updated import GenericResultUpdated
from ..models.generic_result_deleted import GenericResultDeleted
from ..models.generic_result_created import GenericResultCreated
from ..models.contract_type_enum import ContractTypeEnum


class InvoicesService(BaseService):

    @cast_models
    def get_invoice_adjustments_by_contract_id(
        self,
        contract_id: str,
        contract_types: List[ContractTypeEnum] = None,
        types: List[InvoiceAdjustmentTypeEnum] = None,
        statuses: List[InvoiceAdjustmentStatusEnum] = None,
        invoice_id: str = None,
        reporter_id: str = None,
        date_from: str = None,
        date_to: str = None,
        limit: float = None,
        offset: float = None,
    ) -> InvoiceAdjustmentListContainer:
        """Retrieve invoice line items for a given contract id.

        :param contract_id: Deel contract id.
        :type contract_id: str
        :param contract_types: types of contracts to filter, defaults to None
        :type contract_types: List[ContractTypeEnum], optional
        :param types: types of invoice adjustments to filter, defaults to None
        :type types: List[InvoiceAdjustmentTypeEnum], optional
        :param statuses: statuses of invoice adjustment to filter, defaults to None
        :type statuses: List[InvoiceAdjustmentStatusEnum], optional
        :param invoice_id: ID of an existing invoice; NOTE: technically ALL query parameters are strings or array of strings, defaults to None
        :type invoice_id: str, optional
        :param reporter_id: ID of an existing profile; NOTE: technically ALL query parameters are strings or array of strings, defaults to None
        :type reporter_id: str, optional
        :param date_from: to get invoice adjustments submitted on or after given start date (inclusive), defaults to None
        :type date_from: str, optional
        :param date_to: to get invoice adjustments submitted before given end date (excludes records submitted on this date), defaults to None
        :type date_to: 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 offset: Return a page of results after given index of row; NOTE: technically ALL query parameters are strings or array of strings, defaults to None
        :type offset: float, optional
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: InvoiceAdjustmentListContainer
        """

        Validator(str).validate(contract_id)
        Validator(ContractTypeEnum).is_array().is_optional().validate(contract_types)
        Validator(InvoiceAdjustmentTypeEnum).is_array().is_optional().validate(types)
        Validator(InvoiceAdjustmentStatusEnum).is_array().is_optional().validate(
            statuses
        )
        Validator(str).is_optional().validate(invoice_id)
        Validator(str).is_optional().validate(reporter_id)
        Validator(str).is_optional().pattern("^\d{4}-\d{2}-\d{2}$").validate(date_from)
        Validator(str).is_optional().pattern("^\d{4}-\d{2}-\d{2}$").validate(date_to)
        Validator(float).is_optional().min(1).max(99).validate(limit)
        Validator(float).is_optional().min(0).max(999999999).validate(offset)

        serialized_request = (
            Serializer(
                f"{self.base_url}/contracts/{{contract_id}}/invoice-adjustments",
                self.get_default_headers(),
            )
            .add_path("contract_id", contract_id)
            .add_query("contract_types", contract_types)
            .add_query("types", types)
            .add_query("statuses", statuses)
            .add_query("invoice_id", invoice_id)
            .add_query("reporter_id", reporter_id)
            .add_query("date_from", date_from, nullable=True)
            .add_query("date_to", date_to, nullable=True)
            .add_query("limit", limit)
            .add_query("offset", offset)
            .serialize()
            .set_method("GET")
        )

        response = self.send_request(serialized_request)

        return InvoiceAdjustmentListContainer._unmap(response)

    @cast_models
    def get_invoice_adjustments(
        self,
        contract_id: str = None,
        contract_types: List[ContractTypeEnum] = None,
        types: List[InvoiceAdjustmentTypeEnum] = None,
        statuses: List[InvoiceAdjustmentStatusEnum] = None,
        invoice_id: str = None,
        reporter_id: str = None,
        date_from: str = None,
        date_to: str = None,
        limit: float = None,
        offset: float = None,
    ) -> InvoiceAdjustmentListContainer:
        """Retrieve invoice adjustments. You can filter the list by providing additional parameters e.g. contract_id, contract_type etc.

        :param contract_id: Id of an Deel contract., defaults to None
        :type contract_id: str, optional
        :param contract_types: types of contracts to filter, defaults to None
        :type contract_types: List[ContractTypeEnum], optional
        :param types: types of invoice adjustments to filter, defaults to None
        :type types: List[InvoiceAdjustmentTypeEnum], optional
        :param statuses: statuses of invoice adjustment to filter, defaults to None
        :type statuses: List[InvoiceAdjustmentStatusEnum], optional
        :param invoice_id: ID of an existing invoice; NOTE: technically ALL query parameters are strings or array of strings, defaults to None
        :type invoice_id: str, optional
        :param reporter_id: ID of an existing profile; NOTE: technically ALL query parameters are strings or array of strings, defaults to None
        :type reporter_id: str, optional
        :param date_from: to get invoice adjustments submitted on or after given start date (inclusive), defaults to None
        :type date_from: str, optional
        :param date_to: to get invoice adjustments submitted before given end date (excludes records submitted on this date), defaults to None
        :type date_to: 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 offset: Return a page of results after given index of row; NOTE: technically ALL query parameters are strings or array of strings, defaults to None
        :type offset: float, optional
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: InvoiceAdjustmentListContainer
        """

        Validator(str).is_optional().validate(contract_id)
        Validator(ContractTypeEnum).is_array().is_optional().validate(contract_types)
        Validator(InvoiceAdjustmentTypeEnum).is_array().is_optional().validate(types)
        Validator(InvoiceAdjustmentStatusEnum).is_array().is_optional().validate(
            statuses
        )
        Validator(str).is_optional().validate(invoice_id)
        Validator(str).is_optional().validate(reporter_id)
        Validator(str).is_optional().pattern("^\d{4}-\d{2}-\d{2}$").validate(date_from)
        Validator(str).is_optional().pattern("^\d{4}-\d{2}-\d{2}$").validate(date_to)
        Validator(float).is_optional().min(1).max(99).validate(limit)
        Validator(float).is_optional().min(0).max(999999999).validate(offset)

        serialized_request = (
            Serializer(
                f"{self.base_url}/invoice-adjustments", self.get_default_headers()
            )
            .add_query("contract_id", contract_id)
            .add_query("contract_types", contract_types)
            .add_query("types", types)
            .add_query("statuses", statuses)
            .add_query("invoice_id", invoice_id)
            .add_query("reporter_id", reporter_id)
            .add_query("date_from", date_from, nullable=True)
            .add_query("date_to", date_to, nullable=True)
            .add_query("limit", limit)
            .add_query("offset", offset)
            .serialize()
            .set_method("GET")
        )

        response = self.send_request(serialized_request)

        return InvoiceAdjustmentListContainer._unmap(response)

    @cast_models
    def create_invoice_adjustment(
        self, request_body: InvoiceAdjustmentToCreateContainer, recurring: bool = None
    ) -> InvoiceAdjustmentCreatedContainer:
        """Create an invoice adjustment using this endpoint. For example, you can add a bonus, commission, VAT %, deduction etc. to an invoice.

        :param request_body: The request body.
        :type request_body: InvoiceAdjustmentToCreateContainer
        :param recurring: Add this invoice adjustment as recurring, defaults to None
        :type recurring: bool, optional
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: InvoiceAdjustmentCreatedContainer
        """

        Validator(InvoiceAdjustmentToCreateContainer).validate(request_body)
        Validator(bool).is_optional().validate(recurring)

        serialized_request = (
            Serializer(
                f"{self.base_url}/invoice-adjustments", self.get_default_headers()
            )
            .add_query("recurring", recurring)
            .serialize()
            .set_method("POST")
            .set_body(request_body)
        )

        response = self.send_request(serialized_request)

        return InvoiceAdjustmentCreatedContainer._unmap(response)

    @cast_models
    def update_invoice_adjustment_by_id(
        self,
        request_body: InvoiceAdjustmentToUpdateContainer,
        invoice_adjustment_id: str,
    ) -> GenericResultUpdated:
        """Update an existing invoice adjustment. It is not possible to update VAT adjustments, we recommend you to delete the existing VAT adjust and create a new one.

        :param request_body: The request body.
        :type request_body: InvoiceAdjustmentToUpdateContainer
        :param invoice_adjustment_id: ID of an existing invoice adjustment
        :type invoice_adjustment_id: str
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: GenericResultUpdated
        """

        Validator(InvoiceAdjustmentToUpdateContainer).validate(request_body)
        Validator(str).validate(invoice_adjustment_id)

        serialized_request = (
            Serializer(
                f"{self.base_url}/invoice-adjustments/{{invoice_adjustment_id}}",
                self.get_default_headers(),
            )
            .add_path("invoice_adjustment_id", invoice_adjustment_id)
            .serialize()
            .set_method("PATCH")
            .set_body(request_body)
        )

        response = self.send_request(serialized_request)

        return GenericResultUpdated._unmap(response)

    @cast_models
    def delete_invoice_adjustment_by_id(
        self, invoice_adjustment_id: str, reason: str = None
    ) -> GenericResultDeleted:
        """Delete an existing invoice adjustment.

        :param invoice_adjustment_id: ID of an existing invoice adjustment
        :type invoice_adjustment_id: str
        :param reason: Reason for deleting an existing invoice adjustment, defaults to None
        :type reason: str, optional
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: GenericResultDeleted
        """

        Validator(str).validate(invoice_adjustment_id)
        Validator(str).is_optional().validate(reason)

        serialized_request = (
            Serializer(
                f"{self.base_url}/invoice-adjustments/{{invoice_adjustment_id}}",
                self.get_default_headers(),
            )
            .add_path("invoice_adjustment_id", invoice_adjustment_id)
            .add_query("reason", reason)
            .serialize()
            .set_method("DELETE")
        )

        response = self.send_request(serialized_request)

        return GenericResultDeleted._unmap(response)

    @cast_models
    def create_invoice_adjustment_review(
        self,
        invoice_adjustment_id: str,
        request_body: InvoiceAdjustmentReviewToCreateContainer = None,
    ) -> GenericResultCreated:
        """Review an invoice adjustment to approve or decline it.

        :param request_body: The request body., defaults to None
        :type request_body: InvoiceAdjustmentReviewToCreateContainer, optional
        :param invoice_adjustment_id: ID of an existing invoice adjustment
        :type invoice_adjustment_id: str
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: GenericResultCreated
        """

        Validator(InvoiceAdjustmentReviewToCreateContainer).is_optional().validate(
            request_body
        )
        Validator(str).validate(invoice_adjustment_id)

        serialized_request = (
            Serializer(
                f"{self.base_url}/invoice-adjustments/{{invoice_adjustment_id}}/reviews",
                self.get_default_headers(),
            )
            .add_path("invoice_adjustment_id", invoice_adjustment_id)
            .serialize()
            .set_method("POST")
            .set_body(request_body)
        )

        response = self.send_request(serialized_request)

        return GenericResultCreated._unmap(response)

    @cast_models
    def create_invoice_adjustment_reviews(
        self, request_body: InvoiceAdjustmentReviewsToCreateContainer = None
    ) -> GenericResultCreated:
        """Review multiple invoice adjustments to approve or decline a batch.

        :param request_body: The request body., defaults to None
        :type request_body: InvoiceAdjustmentReviewsToCreateContainer, optional
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: GenericResultCreated
        """

        Validator(InvoiceAdjustmentReviewsToCreateContainer).is_optional().validate(
            request_body
        )

        serialized_request = (
            Serializer(
                f"{self.base_url}/invoice-adjustments/many/reviews",
                self.get_default_headers(),
            )
            .serialize()
            .set_method("POST")
            .set_body(request_body)
        )

        response = self.send_request(serialized_request)

        return GenericResultCreated._unmap(response)

    @cast_models
    def get_invoice_adjustments_attachment(
        self, invoice_adjustment_id: str
    ) -> InvoiceAdjustmentAttachmentContainer:
        """Retrieve Attachment file url of specified id.

        :param invoice_adjustment_id: ID of an existing invoice adjustment
        :type invoice_adjustment_id: str
        ...
        :raises RequestError: Raised when a request fails, with optional HTTP status code and details.
        ...
        :return: Successful operation.
        :rtype: InvoiceAdjustmentAttachmentContainer
        """

        Validator(str).validate(invoice_adjustment_id)

        serialized_request = (
            Serializer(
                f"{self.base_url}/invoice-adjustments/{{invoice_adjustment_id}}/attachment",
                self.get_default_headers(),
            )
            .add_path("invoice_adjustment_id", invoice_adjustment_id)
            .serialize()
            .set_method("GET")
        )

        response = self.send_request(serialized_request)

        return InvoiceAdjustmentAttachmentContainer._unmap(response)
