from hashlib import sha256
from math import inf, log
from string import (
    ascii_letters,
    ascii_lowercase,
    ascii_uppercase,
    digits,
    printable,
    punctuation,
)
from typing import List
import rs1101.random_int as ri


hexdigits = digits + ascii_letters[:6]
Hexdigits = hexdigits.upper()
candidate_dict = {
    "u": ascii_uppercase,
    "l": ascii_lowercase,
    "d": digits,
    "p": punctuation,
    "h": hexdigits,
    "H": Hexdigits,
    "a": printable,
}
cddt_default = ["u", "l", "d"]

candidate = ""
for x in cddt_default:
    candidate += candidate_dict[x]


def strength(length, clen):
    return int(log(clen**length, 2))


def random_string(length, candidate=candidate):
    ret = [ri.choice(candidate) for _ in range(length)]
    return "".join(ret)


def s2rs(s, length, candidate=candidate):
    x = sha256(s.encode("utf8")).hexdigest()
    x = int(x, 16)
    ret = int2rs(x, length, candidate)
    return ret


def wash_cddt(cddt: List[str]):
    cddt = sorted(set(cddt))
    exclusive = sorted(["a", "H", "h"])
    for x in exclusive:
        if x in cddt:
            cddt = [x]
            break
    return cddt


def g_candidate(cddt):
    cddt = wash_cddt(cddt)
    candidate_lst = []
    for x in cddt:
        candidate_lst.append(candidate_dict[x])
    candidate = "".join(candidate_lst)
    return candidate


def int2rs(x, length=None, candidate=candidate):
    l = len(candidate)
    ret = []
    remain = length if length else inf
    while x > 0 and remain > 0:
        x, r = divmod(x, l)
        ret.append(candidate[r])
        remain -= 1
    if length and len(ret) < length:
        lack = length - len(ret)
        ret.append(candidate[0] * lack)
    return "".join(ret[::-1])


def rs2int(rs, candidate=candidate):
    l = len(candidate)
    ret = 0
    weight = 1
    for x in rs[::-1]:
        ret += candidate.index(x) * weight
        weight *= l
    return ret


if __name__ == "__main__":
    length = 20
    s = random_string(length)
    strength = strength(length, len(candidate))
    print(s, strength)
    print(hexdigits)
    x = rs2int(s)
    y = int2rs(x)
    assert s == y
    print(s, x, y)
    print(s2rs("嗨", 10))
    print(s2rs("嗨", 20))
