import locale

from datetime import datetime
from decimal import Decimal
from typing import (
    Dict,
    List,
    Optional,
)

import iso8601

from sysactions import get_model

from actions.alerts.model import UserAlertsTable
from utilfunctions import format_currency


class ConfiguredAlertsParser(object):

    def __init__(
        self,
        pos_id,             # type: int
        configured_alerts,  # type: Dict
    ):
        # type: (...) -> None

        self.pos_id = pos_id
        self.model = get_model(self.pos_id)
        self.configured_alerts = configured_alerts
        self.last_updated = self.configured_alerts.pop("last_updated")
        self.condition_formatter = {
            "cancelAmount": self._cancel_amount_fmt,
            "discountAmount": self._discount_amount_fmt,
            "discountPercentage": self._discount_percentage_fmt,
            "onlyAfterFiscalization": self._only_after_fiscalization_fmt,
        }

    def get_data_table(self):
        # type: (...) -> List[str]

        user_ids = set()
        for alert in self.configured_alerts.values():
            user_ids.add(alert.get("user", {}).get("id", "?"))

        user_ids.discard("?")
        alerts_table = []

        for user_id in user_ids:
            user_alerts = self._list_user_alerts(user_id)
            alerts_table.extend(['#'.join(row) for row in user_alerts.build_table_rows()])

        return alerts_table

    def get_last_updated(self):
        # type: (...) -> Optional[datetime]

        if self.last_updated is None:
            return None

        return iso8601.parse_date(self.last_updated)

    def _list_user_alerts(
        self,
        user_id,  # type: str
    ):
        # type: (...) -> UserAlertsTable

        user_alerts_table = None

        for alert in self.configured_alerts.values():
            user = alert.get("user", {})
            if user_id == user.get("id"):
                if user_alerts_table is None:
                    user_alerts_table = UserAlertsTable(
                        user_id=user_id,
                        user_name=user.get("name", "$UNNAMED_USER"),
                    )
                self._list_alert_conditions(
                    alert,
                    user_alerts_table,
                )

        return user_alerts_table

    def _list_alert_conditions(
        self,
        alert,              # type: Dict
        user_alerts_table,  # type: UserAlertsTable
    ):
        # type: (...) -> None

        conditions = alert.get("conditions", {})
        notify_on = "$ALERT_NOTIFY_ON_{}".format(alert.get("notifyOn", "UNKNOW_ALERT"))

        for condition, value in conditions.items():
            formatter = self.condition_formatter.get(condition)
            if formatter is None:
                condition_warn = "{} (?)".format(condition)
                fmt_value = "{} (?)".format(value)
            else:
                condition_warn = None
                fmt_value = formatter(value)

            if fmt_value is not None:
                alert_type = condition_warn or notify_on
                user_alerts_table.add(
                    alert_type,
                    fmt_value,
                )

    def _discount_amount_fmt(
        self,
        value,  # type: str
    ):
        # type: (...) -> str

        return format_currency(self.model, float(value))

    def _cancel_amount_fmt(
        self,
        value,  # type: str
    ):
        # type: (...) -> str

        return format_currency(self.model, float(value))

    @staticmethod
    def _discount_percentage_fmt(
        value,  # type: str
    ):
        # type: (...) -> str

        return _format_percent(value)

    @staticmethod
    def _only_after_fiscalization_fmt(
        _,  # type: str
    ):
        # type: (...) -> None

        return None


def _format_percent(
    value,  # type: str
):
    # type: (...) -> str

    s = locale.format_string("%.2f", Decimal(value))
    return "{}%".format(s.rstrip("0").rstrip(".,"))
