from functools import cache
from collections import Counter, defaultdict

# pool = Counter(map(int, "000226688"))
# counted_digits = (0, 2, 6, 8)
# counts = (3, 2, 2, 2)

# 268

# 208
#  60
#   0


@cache
def choose_n_unique(counts, n):
    if sum(counts) < n:
        raise "you done fucked up"
    if sum(counts) == n:
        return set([counts])
    out = set([])
    for i, count in enumerate(counts):
        if count <= 0:
            continue
        out.update(
            choose_n_unique(counts[:i] + (count - 1,) + counts[i + 1 :], n)
        )
    return out


def sub(a, b):  # a-b
    return tuple(x - y for x, y in zip(a, b))


# print(choose_n_unique(counts, 3))
# print(find_sums(counts))
# print(possible_sums((3, 2, 2, 2)))


def has_len_digit(tup, length):
    for t in tup:
        if len(str(t)) == length:
            return True
    return False


# tup_0, tup_1 = (826,), (0, 0, 6, 820)

# print(has_len_digit(tup_0, 2))
# print(has_len_digit(tup_1, 2))
# exit()


def find_solutions(counted_digits, counts):

    @cache
    def possible_sums(counts):  # sum -> set(tuple(addend))
        if sum(counts) == 0:
            return {0: set()}
        if sum(counts) == 1:
            for i, count in enumerate(counts):
                if count == 0:
                    continue
                digit = counted_digits[i]
            out = {digit: set([(digit,)])}
            return out

        out = defaultdict(set)

        for i, count in enumerate(counts):
            if count <= 0:
                continue
            digit = counted_digits[i]
            sub = possible_sums(counts[:i] + (count - 1,) + counts[i + 1 :])
            for s, tups in sub.items():
                for tup in tups:
                    out[s + digit].add(tuple(sorted((digit,) + tup)))
            # try appending the digit to all sub subms
            for tups in sub.values():
                for tup in tups:
                    for j, val in enumerate(tup):
                        if j > 0 and val == tup[j - 1]:
                            continue
                        new_tup = tuple(
                            sorted((val * 10 + digit,) + tup[:j] + tup[j + 1 :])
                        )
                        out[sum(new_tup)].add(new_tup)
        return out

    out = []
    for counts_0 in choose_n_unique(counts, 3):
        counts_1 = sub(counts, counts_0)
        # print(counts_1)
        possible_0 = possible_sums(counts_0)
        possible_1 = possible_sums(counts_1)
        # print(possible_0.get(268, "nope"))
        # print(possible_1.get(268, "nope"))
        # print()
        for total in possible_0.keys() & possible_1.keys():
            tups_0 = possible_0[total]
            tups_1 = possible_1[total]
            for tup_0 in tups_0:
                for tup_1 in tups_1:
                    if not (has_len_digit(tup_0, 1) or has_len_digit(tup_1, 1)):
                        continue
                    if not (has_len_digit(tup_0, 2) or has_len_digit(tup_1, 2)):
                        continue
                    if not (has_len_digit(tup_0, 3) or has_len_digit(tup_1, 3)):
                        continue
                    out.append((tup_0, tup_1))
    return out


# print(find_solutions(counted_digits=(0, 2, 6, 8), counts=(3, 2, 2, 2)))
import random

rng = random.Random(4)
# best = 100
# for i in range(1000):

#     # rng.randint()
#     def r(radius):
#         return rng.randint(-radius, radius)

#     candidate = find_solutions(
#         counted_digits=(1 + r(1), 2 + r(1), 6 + r(1), 8 + r(1)),
#         counts=(3 + r(1), 2 + r(1), 2 + r(1), 2 + r(1)),
#     )
#     if not candidate:
#         continue

#     if len(candidate) <= best:
#         best = len(candidate)
#         print("yay")
#         for tup in candidate:
#             print("   ", tup)


def counted_digits_and_counts_from_solution(solution):
    s = str(solution)
    for to_remove in "(), ":
        s = s.replace(to_remove, "")
    print(s)
    print("".join(sorted(s)))
    c = Counter(s)
    counted_digits = tuple(int(k) for k in sorted(c))
    counts = tuple(int(c[k]) for k in sorted(c))
    return counted_digits, counts


print(counted_digits_and_counts_from_solution("((261,), (7, 27, 227)))"))
print(find_solutions((1, 2, 6, 7), (1, 4, 1, 3)))
