from .async_gui import AsyncGUI
from .screens import (Screen, PinScreen, Progress,
                      MnemonicScreen, NewMnemonicScreen, RecoverMnemonicScreen,
                      XPubScreen, DerivationScreen, WalletScreen,
                      TransactionScreen, ConfirmWalletScreen, DevSettings)
import rng, asyncio

class SpecterGUI(AsyncGUI):
    """Specter-related GUI"""
    async def get_pin(self, title="Enter your PIN code", get_word=None):
        """
        Async version of the PIN screen.
        Waits for an event that is set in the callback.
        """
        pin_scr = PinScreen(title=title, 
            note="Do you recognize these words?", 
            get_word=get_word)
        await self.load_screen(pin_scr)
        return await pin_scr.result()

    async def setup_pin(self, get_word=None):
        """
        PIN setup screen - first choose, then confirm
        If PIN codes are the same -> return the PIN
        If not -> try again
        """
        pin_scr = PinScreen(title="Choose your PIN code", 
            note="Remember these words, they will stay the same on this device.", 
            get_word=get_word)
        await self.load_screen(pin_scr)
        
        pin1 = await pin_scr.result()

        pin_scr.reset()
        pin_scr.title.set_text("Confirm your PIN code")
        pin2 = await pin_scr.result()

        # check if PIN is the same
        if pin1 == pin2:
            return pin1
        # if not - show an error
        await self.error("PIN codes are different!")
        return await self.setup_pin(get_word)

    async def show_mnemonic(self, mnemonic:str):
        """
        Shows mnemonic on the screen
        """
        scr = MnemonicScreen(mnemonic)
        await self.load_screen(scr)
        return await scr.result()

    async def new_mnemonic(self, generator):
        """
        Generates a new mnemonic and shows it on the screen
        """
        scr = NewMnemonicScreen(generator)
        await self.load_screen(scr)
        return await scr.result()

    async def recover(self, checker=None, lookup=None):
        """
        Asks the user for his recovery phrase.
        checker(mnemonic) - a function that validates recovery phrase
        lookup(word, num_candidates) - a function that 
                returns num_candidates words starting with word
        """
        scr = RecoverMnemonicScreen(checker, lookup)
        await self.load_screen(scr)
        return await scr.result()

    def set_network(self, net):
        """Changes color of the top line on all screens to network color"""
        Screen.network = net

    async def get_derivation(self, title="Enter derivation path"):
        """Asks user to enter derivation path"""
        scr = DerivationScreen(title=title)
        await self.load_screen(scr)
        return await scr.result()

    async def show_xpub(self, xpub, slip132=None, prefix=None, 
                    title="Your master public key"):
        """Shows xpub with slip132 and prefix switches"""
        scr = XPubScreen(xpub=xpub, slip132=slip132, prefix=prefix, title=title)
        await self.load_screen(scr)
        return await scr.result()

    async def show_wallet(self, w, network, idx=None, change=False, remote=False):
        scr = WalletScreen(w, network, idx=idx, change=change)
        if remote:
            await self.open_popup(scr)
        else:
            await self.load_screen(scr)
        res = await scr.result()
        if remote:
            await self.close_popup()
        return res

    async def show_progress(self, host, title, message):
        """
        Shows progress screen and cancel button 
        to cancel communication with the host
        """
        scr = Progress(title, message, button_text="Cancel")
        await self.open_popup(scr)
        asyncio.create_task(self.coro(host, scr))

    async def coro(self, host, scr):
        """
        Waits for one of two events:
        - either user presses something on the screen
        - or host finishes processing
        Also updates progress screen
        """
        while host.in_progress and scr.waiting:
            await asyncio.sleep_ms(30)
            scr.tick(5)
            scr.set_progress(host.progress)
        if host.in_progress:
            host.abort()
        if scr.waiting:
            scr.waiting = False
        await self.close_popup()

    async def confirm_transaction(self, wallet_name, meta, remote=False):
        scr = TransactionScreen(wallet_name, meta)
        if remote:
            await self.open_popup(scr)
        else:
            await self.load_screen(scr)
        res = await scr.result()
        if remote:
            await self.close_popup()
        return res

    async def confirm_new_wallet(self, name, policy, keys):
        scr = ConfirmWalletScreen(name, policy, keys)
        await self.load_screen(scr)
        return await scr.result()

    async def devscreen(self, dev=False, usb=False):
        scr = DevSettings(dev=dev, usb=usb)
        await self.load_screen(scr)
        return await scr.result()