# 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.timesheet_to_update_container import TimesheetToUpdateContainer
from ..models.timesheet_to_create_container import TimesheetToCreateContainer
from ..models.timesheet_status_enum import TimesheetStatusEnum
from ..models.timesheet_reviews_to_create_container import (
    TimesheetReviewsToCreateContainer,
)
from ..models.timesheet_review_to_create_container import (
    TimesheetReviewToCreateContainer,
)
from ..models.timesheet_list_container import TimesheetListContainer
from ..models.timesheet_container import TimesheetContainer
from ..models.invoice_adjustment_created_container import (
    InvoiceAdjustmentCreatedContainer,
)
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 TimesheetsService(BaseService):

    @cast_models
    def get_timesheets_by_contract(
        self,
        contract_id: str,
        contract_types: List[ContractTypeEnum] = None,
        statuses: List[TimesheetStatusEnum] = None,
        reporter_id: str = None,
        date_from: str = None,
        date_to: str = None,
        limit: float = None,
        offset: float = None,
    ) -> TimesheetListContainer:
        """Retrieve a list of timesheets found for a contract.

        :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 statuses: Statuses of timesheets to filter., defaults to None
        :type statuses: List[TimesheetStatusEnum], 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: Filtered results will include records created on or after the provided date., defaults to None
        :type date_from: str, optional
        :param date_to: Filtered results will include records created before the provided 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, 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: TimesheetListContainer
        """

        Validator(str).validate(contract_id)
        Validator(ContractTypeEnum).is_array().is_optional().validate(contract_types)
        Validator(TimesheetStatusEnum).is_array().is_optional().validate(statuses)
        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}}/timesheets",
                self.get_default_headers(),
            )
            .add_path("contract_id", contract_id)
            .add_query("contract_types", contract_types)
            .add_query("statuses", statuses)
            .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 TimesheetListContainer._unmap(response)

    @cast_models
    def get_timesheets(
        self,
        contract_id: str = None,
        contract_types: List[ContractTypeEnum] = None,
        statuses: List[TimesheetStatusEnum] = None,
        reporter_id: str = None,
        date_from: str = None,
        date_to: str = None,
        limit: float = None,
        offset: float = None,
    ) -> TimesheetListContainer:
        """Retrieve a list of timesheets in your Deel account. You can filter the list by providing additional paramters e.g. contract_id, contract_type etc.

        :param contract_id: Id of a 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 statuses: Statuses of timesheets to filter., defaults to None
        :type statuses: List[TimesheetStatusEnum], 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: Filtered results will include records created on or after the provided date., defaults to None
        :type date_from: str, optional
        :param date_to: Filtered results will include records created before the provided 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, 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: TimesheetListContainer
        """

        Validator(str).is_optional().validate(contract_id)
        Validator(ContractTypeEnum).is_array().is_optional().validate(contract_types)
        Validator(TimesheetStatusEnum).is_array().is_optional().validate(statuses)
        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}/timesheets", self.get_default_headers())
            .add_query("contract_id", contract_id)
            .add_query("contract_types", contract_types)
            .add_query("statuses", statuses)
            .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 TimesheetListContainer._unmap(response)

    @cast_models
    def create_timesheet(
        self, request_body: TimesheetToCreateContainer
    ) -> InvoiceAdjustmentCreatedContainer:
        """Submit work for a contractor.

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

        Validator(TimesheetToCreateContainer).validate(request_body)

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

        response = self.send_request(serialized_request)

        return InvoiceAdjustmentCreatedContainer._unmap(response)

    @cast_models
    def get_timesheet_by_id(self, timesheet_id: str) -> TimesheetContainer:
        """Retrieve a single timesheet entry by Id.

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

        Validator(str).validate(timesheet_id)

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

        response = self.send_request(serialized_request)

        return TimesheetContainer._unmap(response)

    @cast_models
    def update_timesheet_by_id(
        self, request_body: TimesheetToUpdateContainer, timesheet_id: str
    ) -> GenericResultUpdated:
        """Update a single timesheet entry.

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

        Validator(TimesheetToUpdateContainer).validate(request_body)
        Validator(str).validate(timesheet_id)

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

        response = self.send_request(serialized_request)

        return GenericResultUpdated._unmap(response)

    @cast_models
    def delete_timesheet_by_id(
        self, timesheet_id: str, reason: str = None
    ) -> GenericResultDeleted:
        """Delete a single timesheet entry.

        :param timesheet_id: ID of an existing timesheet
        :type timesheet_id: str
        :param reason: Reason for deleting an existing timesheet, 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(timesheet_id)
        Validator(str).is_optional().validate(reason)

        serialized_request = (
            Serializer(
                f"{self.base_url}/timesheets/{{timesheet_id}}",
                self.get_default_headers(),
            )
            .add_path("timesheet_id", timesheet_id)
            .add_query("reason", reason)
            .serialize()
            .set_method("DELETE")
        )

        response = self.send_request(serialized_request)

        return GenericResultDeleted._unmap(response)

    @cast_models
    def create_timesheet_review(
        self, timesheet_id: str, request_body: TimesheetReviewToCreateContainer = None
    ) -> GenericResultCreated:
        """Review a timesheet to approve or decline submitted work.

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

        Validator(TimesheetReviewToCreateContainer).is_optional().validate(request_body)
        Validator(str).validate(timesheet_id)

        serialized_request = (
            Serializer(
                f"{self.base_url}/timesheets/{{timesheet_id}}/reviews",
                self.get_default_headers(),
            )
            .add_path("timesheet_id", timesheet_id)
            .serialize()
            .set_method("POST")
            .set_body(request_body)
        )

        response = self.send_request(serialized_request)

        return GenericResultCreated._unmap(response)

    @cast_models
    def create_timesheet_reviews(
        self, request_body: TimesheetReviewsToCreateContainer = None
    ) -> GenericResultCreated:
        """Review a batch of timesheets to approve or reject submitted work.

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

        Validator(TimesheetReviewsToCreateContainer).is_optional().validate(
            request_body
        )

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

        response = self.send_request(serialized_request)

        return GenericResultCreated._unmap(response)
