from micropython import const

from trezor import ui
from trezor.messages.AuthorizeCoinJoin import AuthorizeCoinJoin
from trezor.messages.Success import Success
from trezor.strings import format_amount
from trezor.ui.text import Text

from apps.base import set_authorization
from apps.common.confirm import require_confirm, require_hold_to_confirm
from apps.common.paths import validate_path

from . import addresses
from .authorization import FEE_PER_ANONYMITY_DECIMALS, CoinJoinAuthorization
from .common import BIP32_WALLET_DEPTH
from .keychain import get_keychain_for_coin

if False:
    from trezor import wire

_MAX_COORDINATOR_LEN = const(18)


async def authorize_coinjoin(ctx: wire.Context, msg: AuthorizeCoinJoin,) -> Success:
    # We cannot use the @with_keychain decorator here, because we need the keychain
    # to survive the function exit. The ownership of the keychain is transferred to
    # the CoinJoinAuthorization object, which takes care of its destruction.
    keychain, coin = await get_keychain_for_coin(ctx, msg.coin_name)

    try:
        if len(msg.coordinator) > _MAX_COORDINATOR_LEN or not all(
            32 <= ord(x) <= 126 for x in msg.coordinator
        ):
            raise wire.DataError("Invalid coordinator name.")

        if not msg.address_n:
            raise wire.DataError("Empty path not allowed.")

        await validate_path(
            ctx,
            addresses.validate_full_path,
            keychain,
            msg.address_n + [0] * BIP32_WALLET_DEPTH,
            coin.curve_name,
            coin=coin,
            script_type=msg.script_type,
        )

        text = Text("Authorize CoinJoin", ui.ICON_RECOVERY)
        text.normal("Do you really want to")
        text.normal("take part in a CoinJoin")
        text.normal("transaction at:")
        text.mono(msg.coordinator)
        await require_confirm(ctx, text)

        text = Text("Authorize CoinJoin", ui.ICON_RECOVERY)
        if msg.fee_per_anonymity is not None:
            text.normal("Fee per anonymity set:")
            text.bold(
                "{} %".format(
                    format_amount(msg.fee_per_anonymity, FEE_PER_ANONYMITY_DECIMALS)
                )
            )
        text.normal("Maximum total fees:")
        text.bold(
            "{} {}".format(
                format_amount(msg.max_total_fee, coin.decimals), coin.coin_shortcut
            )
        )
        await require_hold_to_confirm(ctx, text)

        set_authorization(CoinJoinAuthorization(msg, keychain, coin))

    except BaseException:
        keychain.__del__()
        raise

    return Success(message="CoinJoin authorized")
