#!/usr/bin/python3

import os
import sys
from typing import List, Optional

sys.path.insert(0, "/usr/local/mgr5/lib/python")
from billmgr.exception import log_backtrace
from billmgr.logger import Logger, init_logging, get_logger
from billmgr.modules.paymentcgi import PageType, run_cgi, RegularPaymentCGI
from billmgr.payment import set_in_pay
from billmgr.paymentreceipt.enumerations import PaymentReceiptType

from paymaster.api.client import PayMasterAPI
from paymaster.api.enumerations import (
    PaymentSubject as PayMasterPaymentSubject,
    PaymentMethod as PayMasterPaymentMethod, VatType, ItemMeasurementUnit
)
from paymaster.api.parameters import PaymentGetURLParameters
from paymaster.exceptions import PayMasterException
from paymaster.utils import (
    format_email, format_phone, generate_notification_token, get_notification_url, json_dict
)


MODULE: str = "paymasterv2payment"

init_logging(MODULE)
logger: Logger = get_logger(MODULE)


class PayMasterPaymentCGI(RegularPaymentCGI):

    def __init__(self) -> None:
        super().__init__()

        logger.debug(f"user_params = {self.user_params}")
        logger.debug(f"paymethod_params = {self.paymethod_params}")
        logger.debug(f"payment_params = {self.payment_params}")
        logger.debug(f"items_params = {self.items_params}")

        self._idempotency_key: Optional[str] = self.payment_params.get("randomnumber")
        is_test_mode: bool = self.paymethod_params["testmode"] == "on"
        is_stored_payment: bool = self.payment_params.get("store_payment") == "on"

        callback_url: Optional[str] = None
        are_notifications_enabled: bool = self.paymethod_params["allownotifications"] == "on"
        if are_notifications_enabled:
            callback_url = get_notification_url(
                custom_url=self.paymethod_params.get("notification_url"),
                hostname=os.environ["HTTP_HOST"],
                storepayment="yes" if is_stored_payment else None,
                recurringid=self.payment_params.get("recurring", None),
                notificationtoken=generate_notification_token(
                    merchant_id=self.paymethod_params["merchant_id"],
                    api_token=self.paymethod_params["api_token"],
                    id_=int(self.elid())
                )
            )

        receipt: Optional[PaymentGetURLParameters.Receipt] = None
        are_receipts_enabled_via_paymethod: bool = \
            self.paymethod_params.get("paymentreceipt_type") == PaymentReceiptType.SELF
        if are_receipts_enabled_via_paymethod:
            api_items: List[PaymentGetURLParameters.Receipt.Item] = list()
            for item in self.items_params:
                api_items.append(
                    PaymentGetURLParameters.Receipt.Item(
                        name=item["locale_name"],
                        quantity=1,
                        price=float(item["amount"]),
                        vat_type=VatType.parse(float(item["taxrate"])),
                        payment_subject=PayMasterPaymentSubject.parse(int(item["payment_object"])),
                        payment_method=PayMasterPaymentMethod.parse(int(item["payment_method"])),
                        measure=ItemMeasurementUnit.PIECE
                    )
                )
            receipt = PaymentGetURLParameters.Receipt(
                client=PaymentGetURLParameters.Receipt.Client(
                    email=format_email(self.payment_params.get("useremail")),
                    phone=format_phone(self.user_params.get("phone"))
                ),
                items=api_items
            )

        self._get_url_parameters = PaymentGetURLParameters(
            invoice=PaymentGetURLParameters.Invoice(
                description=self.payment_params["description"],
                order=self.elid()
            ),
            amount=PaymentGetURLParameters.Amount(
                value=float(self.payment_params["paymethodamount"]),
                currency=self.currency_params["iso"]
            ),
            test_mode=is_test_mode,
            tokenization=None if not is_stored_payment else PaymentGetURLParameters.Tokenization(
                type_="recurring",
                purpose=f"Create stored payment method initialized by payment #{self.elid()}",
                callback_url=callback_url
            ),
            payment_method=self.paymethod_params["payment_method"],
            protocol=PaymentGetURLParameters.Protocol(
                return_url=self.get_page(PageType.Pending),
                callback_url=callback_url
            ),
            customer=PaymentGetURLParameters.Customer(
                email=format_email(self.user_params.get("email")),
                phone=format_phone(self.user_params.get("phone")),
                account=str(self.user_params.get("user_id"))
            ),
            receipt=receipt
        )

    def process(self):
        try:
            api = PayMasterAPI(
                merchant_id=self.paymethod_params["merchant_id"],
                auth_token=self.paymethod_params["api_token"],
                logger=logger
            )
            response: json_dict = api.payment.get_url(
                self._get_url_parameters,
                self._idempotency_key
            )
            set_in_pay(
                payment_id=int(self.elid()),
                external_id=str(response.get("paymentId"))
            )
            self.redirect_to_url(str(response.get("url")))
        except PayMasterException as error:
            logger.error(error)
            self.redirect_to_url(self.get_page(PageType.Fail))
        except Exception:
            log_backtrace()
            self.redirect_to_url(self.get_page(PageType.Fail))


if __name__ == "__main__":
    run_cgi(PayMasterPaymentCGI)
