import hashlib
import asyncio
import unicodedata
from binascii import hexlify
from secrets import randbits

from lbry.crypto.hash import hmac_sha512
from . import words


def get_languages():
    return words.languages


def normalize(phrase: str) -> str:
    return ' '.join(unicodedata.normalize('NFKD', phrase).lower().split())


def is_phrase_valid(language, phrase):
    local_words = getattr(words, language)
    for word in normalize(phrase).split():
        if word not in local_words:
            return False
    return bool(phrase)


def sync_generate_phrase(language: str) -> str:
    local_words = getattr(words, language)
    entropy = randbits(132)
    nonce = 0
    while True:
        nonce += 1
        i = entropy + nonce
        word_buffer = []
        while i:
            word_buffer.append(local_words[i % 2048])
            i //= 2048
        seed = ' '.join(word_buffer)
        if hexlify(hmac_sha512(b"Seed version", seed.encode())).startswith(b"01"):
            break
    return seed


def sync_derive_key_from_phrase(phrase: str) -> bytes:
    return hashlib.pbkdf2_hmac('sha512', normalize(phrase).encode(), b'lbryum', 2048)


async def generate_phrase(language: str) -> str:
    return await asyncio.get_running_loop().run_in_executor(
        None, sync_generate_phrase, language
    )


async def derive_key_from_phrase(phrase: str) -> bytes:
    return await asyncio.get_running_loop().run_in_executor(
        None, sync_derive_key_from_phrase, phrase
    )