#
# halvening raffle algorithm for independent verify
# of RSIC halvening raffle results
#
#  ███████████    █████████  █████   █████████ 
# ░░███░░░░░███  ███░░░░░███░░███   ███░░░░░███
#  ░███    ░███ ░███    ░░░  ░███  ███     ░░░ 
#  ░██████████  ░░█████████  ░███ ░███         
#  ░███░░░░░███  ░░░░░░░░███ ░███ ░███         
#  ░███    ░███  ███    ░███ ░███ ░░███     ███
#  █████   █████░░█████████  █████ ░░█████████ 
# ░░░░░   ░░░░░  ░░░░░░░░░  ░░░░░   ░░░░░░░░░  
#
# reference:
# - RSIC: https://www.ord.io/57066799
# - Pooling: https://www.ord.io/67645350
#

import random

import csv
import sys

def select_winners(num_lots, num_winners, seed):
    random.seed(seed)  # seed the random number generator for reproducible
    winners = []  # use a list for maintain the order of draw
    while len(winners) < num_winners:
        selected = random.randint(0, num_lots - 1)  # random select lot
        if selected not in winners:  # ensure lot has not been select before
            winners.append(selected)  # add to list, maintain draw order

    return winners  # return winners in the order they drawn


def raffle_rsics(num_lots, lots_for_rsic, blockhash):
    # convert blockhash to number
    blockhash_int = int(blockhash, 16)

    # use block number as seed for selecting winners
    winners = select_winners(num_lots, 5, blockhash_int)


    # enumerate lots to map to winning RSIC
    winning_rsics = [-1, -1, -1, -1, -1]
    current_lot = 0
    found_winners = 0
    for rsic in range(len(lots_for_rsic)):
        for i in range(lots_for_rsic[rsic]):
            if current_lot in winners:
                winning_rsics[winners.index(current_lot)] = rsic
                found_winners += 1
                if found_winners == 5:
                    break
            current_lot += 1

    return winning_rsics


def rsic_halvening_raffle(lots_for_rsic, rsic_pooled, blockhash):
    # total number of lots
    num_lots = sum(lots_for_rsic)
    num_pooled_lots = sum([lots_for_rsic[rsic] for rsic in rsic_pooled])

    print(
        f"Running RSIC halvening raffle with {len(lots_for_rsic)} RSICs ({len((rsic_pooled))} pooled) and {num_lots} lots ({num_pooled_lots} pooled) for blockhash {blockhash}"
    )

    # select the winning lots
    winners = raffle_rsics(num_lots, lots_for_rsic, blockhash)
    print(f"Winning RSICs: {winners}")

    # allocate prizes
    allocation = [0] * len(lots_for_rsic)

    # allocate rewards based on the winning lots
    for i, rsic in enumerate(winners):
        prize = 210000000 * (5 - i) # many runes

        if not rsic in rsic_pooled:
            print(f"Allocating prize #{i+1} of {prize} to solo RSIC {rsic}")
            # all prize to winner is very lucky congrats!
            allocation[rsic] += prize
        else:
            # 10% to winner is lucky
            winner_share = prize // 10
            # 90% to pool is great
            pool_share = prize * 9 // 10

            print(
                f"Allocating prize #{i+1} of {prize} for pooled RSIC {rsic} ({winner_share} to winner, {pool_share} to pool)"
            )
            allocation[rsic] += winner_share

            pool_share_allocated = 0
            for pooled_rsic in rsic_pooled:
                current_share = (
                    pool_share * lots_for_rsic[pooled_rsic] // num_pooled_lots
                )
                print(f"Allocating {current_share} to pooled RSIC {pooled_rsic}")
                pool_share_allocated += current_share
                allocation[pooled_rsic] += current_share

            # distribute any remaining share (from remainders in dividing shares) to winner
            allocation[rsic] += pool_share - pool_share_allocated
            print(
                f"Allocated {pool_share} to pool and {prize - pool_share} + {pool_share-pool_share_allocated} to winner"
            )
    return allocation

def test_raffle():
    # some sample data for testing small

    lots_for_rsic = [42, 69, 4269, 2121, 6969, 111, 787, 888, 900, 1000, 0, 13]
    rsic_pooled = [3, 5, 7, 9]
    blockhash = "0000000000000000000f1c8"

    allocation = rsic_halvening_raffle(lots_for_rsic, rsic_pooled, blockhash)

    print(f"allocated {allocation} to RSICs")

# sample main function - for run independent verify
def main(input_tsv, blockhash):
    with open(input_tsv, 'r', newline='') as file:
        reader = csv.reader(file, delimiter='\t')
        lots_for_rsic = []
        rsic_pooled = []
        for row in reader:
            rsic_number, num_lots, is_pooled = int(row[0]), int(row[1]), row[2] == '1'
            lots_for_rsic.append(num_lots)
            if is_pooled:
                rsic_pooled.append(rsic_number)

    allocation = rsic_halvening_raffle(lots_for_rsic, rsic_pooled, blockhash)
    
    output_tsv = input_tsv.replace('.tsv', '-results.tsv')
    with open(output_tsv, 'w', newline='') as file:
        writer = csv.writer(file, delimiter='\t')
        for rsic_number, alloc in enumerate(allocation):
            if alloc > 0:
                writer.writerow([rsic_number, alloc])

if __name__ == "__main__":
    test_raffle()
    
    if len(sys.argv) != 3:
        print("need input.tsv and blockhash argument")
    else:
        input_tsv = sys.argv[1]
        blockhash = sys.argv[2]
        main(input_tsv, blockhash)
