"""
Проверка розыгрыша хэллоуинского конкурса Raspika (октябрь 2026).

Что нужно:
  1. Список билетов, опубликованный в канале t.me/Raspika 31 октября после 20:00
     (строки вида «4821:12.5» — номер участника и число билетов), сохранить в файл list.txt.
  2. Python 3 (https://python.org), больше ничего не нужно.

Запуск:
  python hw-draw.py list.txt
Скрипт сам скачает случайное число раунда drand 6602726 (выходит 1 ноября 2026 в 12:00 по Омску)
с api.drand.sh. Если интернета нет, можно передать его вручную:
  python hw-draw.py list.txt <randomness в hex>

Как выбираются победители:
  1. Сертификат 4 000 ₽ — участник с наибольшим числом билетов (при равенстве — жребий тем же drand).
  2. Остальные участники участвуют в розыгрыше по билетам: шанс пропорционален числу билетов
     (половинка билета = половина шанса), один человек выигрывает максимум один приз.
     Первые 5 выпавших — 1 000 ₽, следующие 10 — 500 ₽, ещё 5 — запасные (если победитель
     не ответит за 7 дней).
"""
import hashlib
import json
import random
import sys
import urllib.request

ROUND = 6602726
TIERS = [(5, 1000), (10, 500)]
RESERVE = 5


def load(path):
    text = open(path, encoding="utf-8").read().strip().replace("\r\n", "\n")
    rows = []
    for line in text.splitlines():
        line = line.strip()
        if line:
            num, total = line.split(":")
            rows.append((int(num), float(total)))
    return text, rows


def drand(rnd):
    for base in ("https://api.drand.sh", "https://drand.cloudflare.com", "https://api2.drand.sh"):
        try:
            with urllib.request.urlopen(f"{base}/public/{rnd}", timeout=20) as r:
                return json.load(r)["randomness"]
        except Exception:
            continue
    raise SystemExit("Не удалось получить число drand: передайте его вторым аргументом.")


def draw(rows, randomness_hex):
    rows = sorted(rows)                                   # по номеру участника, как в списке
    rng = random.Random(int(randomness_hex, 16))
    top = max((t for _, t in rows), default=0)
    tied = [n for n, t in rows if t == top] if top else []
    leader = rng.choice(tied) if tied else None
    pool = [(n, int(round(t * 2))) for n, t in rows if n != leader]   # вес = билеты × 2
    order = []
    for _ in range(min(sum(k for k, _ in TIERS) + RESERVE, len(pool))):
        x = rng.randrange(sum(w for _, w in pool))
        for i, (n, w) in enumerate(pool):
            if x < w:
                order.append(n)
                pool.pop(i)
                break
            x -= w
    return leader, tied, order


def main():
    if len(sys.argv) < 2:
        raise SystemExit(__doc__)
    text, rows = load(sys.argv[1])
    print("Участников в списке:", len(rows))
    print("SHA-256 списка:", hashlib.sha256(text.encode()).hexdigest(), "(должен совпасть с опубликованным)")
    hexr = sys.argv[2] if len(sys.argv) > 2 else drand(ROUND)
    print("Раунд drand:", ROUND, "| randomness:", hexr)
    leader, tied, order = draw(rows, hexr)
    print()
    print("🥇 4 000 ₽ — №", leader, f"(жребий среди равных: {tied})" if len(tied) > 1 else "")
    i = 0
    for k, amount in TIERS:
        for n in order[i:i + k]:
            print(f"🎲 {amount} ₽ — №", n)
        i += k
    print("Запасные по порядку:", ", ".join(f"№{n}" for n in order[i:]))


if __name__ == "__main__":
    main()
