"""
hubspot properties api
"""
from typing import Dict, Optional
from hubspot3.base import BaseClient
from hubspot3.globals import (
    OBJECT_TYPE_COMPANIES,
    OBJECT_TYPE_CONTACTS,
    OBJECT_TYPE_DEALS,
    OBJECT_TYPE_LINE_ITEMS,
    OBJECT_TYPE_PRODUCTS,
    VALID_PROPERTY_DATA_TYPES,
    VALID_PROPERTY_WIDGET_TYPES,
    DATA_TYPE_ENUM,
)
from hubspot3.utils import get_log


PROPERTIES_API_VERSION = {
    OBJECT_TYPE_COMPANIES: "1",
    OBJECT_TYPE_CONTACTS: "1",
    OBJECT_TYPE_DEALS: "1",
    OBJECT_TYPE_LINE_ITEMS: "2",
    OBJECT_TYPE_PRODUCTS: "2",
}


class PropertiesClient(BaseClient):
    """
    The hubspot3 Properties client uses the _make_request method to call the
    API for data.  It returns a python object translated from the json returned
    """

    # Used to store a current object_type. This will be used in `_get_path` to generate the
    # appropriate path to use.
    _object_type = None

    def __init__(self, *args, **kwargs):
        super(PropertiesClient, self).__init__(*args, **kwargs)
        self.log = get_log("hubspot3.properties")

    def _get_path(self, subpath):
        return "properties/v{}/{}/properties/{}".format(
            PROPERTIES_API_VERSION[self._object_type], self._object_type, subpath
        )

    @staticmethod
    def _validate(
        data_type: Optional[str], widget_type: Optional[str], extra_params: dict
    ) -> None:
        if data_type:
            if data_type not in VALID_PROPERTY_DATA_TYPES:
                raise ValueError(
                    "Invalid data type for property. Valid data types are: {}".format(
                        VALID_PROPERTY_DATA_TYPES
                    )
                )

            if data_type == DATA_TYPE_ENUM and (
                not extra_params or not extra_params.get("options")
            ):
                raise ValueError(
                    "Invalid data for updating an enumeration type. "
                    "Its 'options' have to be specified."
                )

        if widget_type and widget_type not in VALID_PROPERTY_WIDGET_TYPES:
            raise ValueError(
                "Invalid widget type for property. Valid widget types are: {}".format(
                    VALID_PROPERTY_WIDGET_TYPES
                )
            )

    def create(
        self,
        object_type: str,
        code: str,
        label: str,
        description: str,
        group_code: str,
        data_type: str,
        widget_type: str,
        extra_params: dict = None,
    ) -> Dict:
        """
        Create a new custom property on hubspot.
        """
        extra_params = extra_params or {}

        self._validate(data_type, widget_type, extra_params)

        # Save the current object type.
        self._object_type = object_type

        return self._call(
            "",
            method="POST",
            data={
                "name": code,
                "label": label,
                "description": description,
                "groupName": group_code,
                "type": data_type,
                "fieldType": widget_type,
                **extra_params,
            },
        )

    def update(
        self,
        object_type: str,
        code: str,
        label: str = None,
        description: str = None,
        group_code: str = None,
        data_type: str = None,
        widget_type: str = None,
        extra_params: dict = None,
    ) -> Dict:
        """
        Update a custom property on hubspot.
        """

        extra_params = extra_params or {}

        self._validate(data_type, widget_type, extra_params)

        # Save the current object type.
        self._object_type = object_type

        fields = {
            "label": label,
            "description": description,
            "groupName": group_code,
            "type": data_type,
            "fieldType": widget_type,
            **extra_params,
        }
        data = {key: value for key, value in fields.items() if value is not None}

        return self._call("named/{}".format(code), method="PUT", data=data)

    def get_all(self, object_type):
        """Retrieve all the custom properties."""

        # Save the current object type.
        self._object_type = object_type

        return self._call(
            "", method="GET", params={"properties": ["name", "label", "description"]}
        )

    def get(self, object_type: str, code: str):
        """Retrieve a property."""

        # Save the current object type.
        self._object_type = object_type

        return self._call("named/{}".format(code), method="GET")

    def delete(self, object_type, code):
        """Delete a custom property."""

        # Save the current object type.
        self._object_type = object_type

        return self._call("named/{}".format(code), method="DELETE")

    def delete_all(self, object_type):
        """Delete all the custom properties. Please use it carefully."""
        props_data = self.get_all(object_type)

        for prop_data in props_data:
            if not prop_data["hubspotDefined"]:
                self.delete(object_type, prop_data["name"])
