#! /usr/bin/python
# -*- coding: utf-8 -*-
# LICENSE: WTFPL <http://www.wtfpl.net/txt/copying/>
# Script is really ugly and hacky; please don't [[:zh:吐槽]] ;)

from __future__ import absolute_import, unicode_literals

import collections
import datetime
import re

import pywikibot
from pywikibot.data import api

YEAR = datetime.datetime.now().year - 1

ELIGIBILITY = {
    'register': {
        'before': pywikibot.Timestamp(YEAR + 1, 1, 1),
    },
    'edits': {
        'before': pywikibot.Timestamp(YEAR + 1, 1, 1),
        'atleast': 75,
        'includedeleted': False
    }
}

NUM_VOTES = 3
NUM_VOTES_DIG = pywikibot.Timestamp(YEAR + 1, 1, 1)

site = pywikibot.Site('commons', 'commons')

# FIXME: find a better way to handle renamed users
RENAMED_USERS = {
    'TheFallenOneGOTH': 'QuickWhitt7',
    'ClamsioPL': 'McReyer',
    'ବିକାଶଓଝା': 'Bikash Ojha',
    'Jacek Graniecki': 'Pawel Dymanski',
    'Werónika': 'Woebegone',
    'NgYShung': 'QianCheng',
    'FISKA BARSA': 'VISKA BARSA'
}


def if_redirct_get_target(page):
    if page.isRedirectPage():
        page = page.getRedirectTarget()
        if page.namespace() == 6:
            page = pywikibot.FilePage(page)
    return page


candidates_page = pywikibot.Page(
    site, 'Commons:Picture of the Year/%s/Candidates/R2' % YEAR)
candidates_dict = collections.defaultdict(set)

ingallery = False
for line in candidates_page.text.split('\n'):
    line = line.strip()

    if not line:
        continue

    elif line.startswith('<gallery'):
        assert not ingallery
        ingallery = True
    elif line == '</gallery>':
        assert ingallery
        ingallery = False
    else:
        if ingallery:
            reobj = re.match(r'([^|]+?)\|.+', line)
            candidates_dict[pywikibot.FilePage(site, reobj.group(1))]
        else:
            raise RuntimeError


all_voters = {}

for candidate, voters in candidates_dict.items():
    votepage = pywikibot.Page(
        site,
        'Commons:Picture of the Year/2016/R2/v/' +
        candidate.title(withNamespace=False))
    for line in if_redirct_get_target(votepage).text.split('\n'):
        if not line:
            continue
        if line in ['{{autotranslate|base=POTY2016/header}}',
                    '{{-}}{{POTY2016/Roundheader}}']:
            continue
        if line == '== {{int:Ratinghistory-table-votes}} ==':
            continue
        reobj = re.match(r'# *\[\[User:([^\]\|]+)(?:\|\1)\]\]$', line)
        assert reobj, 'Unexpected line: ' + line

        voter = pywikibot.User(
            site, RENAMED_USERS.get(reobj.group(1), reobj.group(1)))

        if voter in voters:
            pywikibot.warn('{}: {} already voted'.format(candidate, voter))
        voters.add(voter)
        all_voters[voter] = None


def check_eligibility(voter):
    sul = site._simple_request(
        action='query',
        meta='globaluserinfo',
        guiprop='merged',
        guiuser=voter.username
    ).submit()
    try:
        sul = sul['query']['globaluserinfo']['merged']
    except KeyError:
        pywikibot.exception('{}: Unmerged account?!'.format(voter))
        return False
    sul = sorted(sul, key=lambda item: item['editcount'], reverse=True)

    eligible_register = eligible_edits = False
    for sulentry in sul:
        eligible_register = eligible_register or (
            min(
                pywikibot.Timestamp.fromISOformat(sulentry['registration']),
                pywikibot.Timestamp.fromISOformat(sulentry['timestamp'])
            ) < ELIGIBILITY['register']['before'])
        if not eligible_edits:
            # Being lazy
            if sulentry['editcount'] >= ELIGIBILITY['edits']['atleast']:
                try:
                    sul_site = site.fromDBName(sulentry['wiki'])
                except pywikibot.exceptions.UnknownFamily:
                    pywikibot.exception(
                        'Failed to get Site object for {}, skipping'.format(
                            sulentry['wiki']))
                    continue
                # sul_user = pywikibot.User(sul_site, voter.username)
                if ELIGIBILITY['edits']['includedeleted']:
                    raise NotImplementedError(
                        'counting deleted edits is not implemented')
                else:
                    contribs = sul_site.usercontribs(
                        voter.username,
                        start=ELIGIBILITY['edits']['before'],
                        total=ELIGIBILITY['edits']['atleast']
                    )
                    eligible_edits = (len(list(contribs)) >=
                                      ELIGIBILITY['edits']['atleast'])

        if eligible_register and eligible_edits:
            return True

    return False


for voter in all_voters:
    eligible = check_eligibility(voter)
    all_voters[voter] = eligible
    pywikibot.output('{}: {}'.format(
        voter, 'eligible' if eligible else 'ineligible'))


voter_votes = collections.defaultdict(set)


pywikibot.output('================')
for candidate, voters in candidates_dict.items():
    pywikibot.output('------------------')
    pywikibot.output('Candidate: {}'.format(candidate))

    for voter in voters.copy():
        assert all_voters[voter] is not None
        if not all_voters[voter]:
            pywikibot.output('Drop ineligible vote from {}'.format(voter))
            voters.remove(voter)
        else:
            voter_votes[voter].add(candidate)

    pywikibot.output('Total votes: {}'.format(len(voters)))


toomanyvotes = collections.defaultdict(set)


def fixup_toomanyvotes(voter, candidates):
    votepage_prefix = 'Commons:Picture of the Year/%d/R2/v/' % YEAR
    ucgen = site._generator(api.ListGenerator,
                            type_arg="usercontribs",
                            ucprop="title|sizediff",
                            ucuser=voter,
                            ucnamespace=4,
                            ucend=str(NUM_VOTES_DIG))

    last_votes = set()
    for contrib in ucgen:
        # print contrib
        if contrib['sizediff'] < 0 or not contrib['title'].startswith(
                votepage_prefix):
            continue

        candidate = pywikibot.FilePage(
            site, contrib['title'][len(votepage_prefix):])
        if candidate in candidates:
            pywikibot.output('Keep {}'.format(candidate))
            last_votes.add(candidate)

            if len(last_votes) == 3:
                break

    drops = candidates - last_votes
    for candidate in drops:
        pywikibot.output('Drop {}'.format(candidate))
        toomanyvotes[candidate].add(voter)


pywikibot.output('================')
for voter, candidates in voter_votes.items():
        pywikibot.output('------------------')
        pywikibot.output('{} voted too may candidates'.format(voter))
        fixup_toomanyvotes(voter, candidates)


pywikibot.output('================')
for candidate, voters in toomanyvotes.items():
    pywikibot.output('------------------')
    pywikibot.output('Candidate: {}'.format(candidate))

    for voter in voters:
        pywikibot.output('Drop too-many-votes vote from {}'.format(voter))
        candidates_dict[candidate].remove(voter)

    pywikibot.output('Total votes: {}'.format(len(candidates_dict[candidate])))


def get_tops(dct, num):
    dct = collections.OrderedDict(
        sorted(dct.items(), key=lambda i: i[1], reverse=True))
    last_i = 0
    last_v = None
    for i, (key, val) in enumerate(dct.items(), 1):
        if val != last_v:
            last_v = val
            last_i = i

        if last_i > num:
            break

        yield last_i, key


pywikibot.output('================')
for i, candiate in get_tops(
        {c: len(v) for c, v in candidates_dict.items()}, float("inf")):
    pywikibot.output('{title}| #{i}, {n} votes'.format(
                        i=i, n=len(candidates_dict[candiate]),
                        title=candiate.title(withNamespace=False)))
[[commons:User:P.khiao]]: eligible
[[commons:User:Mirer]]: eligible
[[commons:User:Kathegaara]]: eligible
[[commons:User:What'sGoingOn]]: eligible
[[commons:User:FriedhelmW]]: eligible
[[commons:User:Jkadavoor]]: eligible
[[commons:User:Toxygen]]: eligible
[[commons:User:Sleyece]]: eligible
[[commons:User:Avdonin]]: eligible
[[commons:User:123Jon4]]: eligible
[[commons:User:Vadimzer]]: eligible
[[commons:User:Quercusechinus]]: eligible
[[commons:User:양건희]]: eligible
[[commons:User:Icondaemon]]: eligible
[[commons:User:Galaktiker]]: eligible
[[commons:User:Ante Vranković]]: eligible
[[commons:User:Олег Граченко]]: eligible
[[commons:User:Blauendorn]]: eligible
[[commons:User:JeanPersil]]: eligible
[[commons:User:Mvolz]]: eligible
[[commons:User:Iopq]]: eligible
[[commons:User:Lionel Allorge]]: eligible
[[commons:User:Junafani]]: eligible
[[commons:User:Fringio]]: eligible
[[commons:User:Sara Nabih]]: eligible
[[commons:User:SeMelmoth]]: eligible
[[commons:User:Paulmacht]]: eligible
[[commons:User:Sunpriat]]: eligible
[[commons:User:Rackham]]: eligible
[[commons:User:An Macanese]]: eligible
[[commons:User:Simisa]]: eligible
[[commons:User:Jgcab]]: eligible
[[commons:User:Muhammad Abul-Futooh]]: eligible
[[commons:User:Misahaqn2]]: eligible
[[commons:User:Londonjackbooks]]: eligible
[[commons:User:LIVE NIEUWS]]: eligible
[[commons:User:Kruusamägi]]: eligible
[[commons:User:GeoO]]: eligible
[[commons:User:Walrus068]]: eligible
[[commons:User:AlMare]]: eligible
[[commons:User:Asterixtintin]]: eligible
[[commons:User:Salavat]]: eligible
[[commons:User:Zamaster4536]]: eligible
[[commons:User:3555Colin]]: eligible
[[commons:User:Diako1971]]: eligible
[[commons:User:Townie]]: eligible
[[commons:User:Albinfo]]: eligible
[[commons:User:Тиверополник]]: eligible
[[commons:User:DiegoMera1503]]: eligible
[[commons:User:Y2kbug]]: eligible
[[commons:User:Wearsunscreen]]: eligible
[[commons:User:Aspargos]]: eligible
[[commons:User:Suresh.vinay]]: eligible
[[commons:User:Fuxx]]: eligible
[[commons:User:LordHello1]]: eligible
[[commons:User:YaganZ]]: eligible
[[commons:User:Ylojarvenjaa]]: eligible
[[commons:User:Jaycarlson]]: eligible
[[commons:User:Tonton Bernardo]]: eligible
[[commons:User:Ashorocetus]]: eligible
[[commons:User:Politrukki]]: eligible
[[commons:User:Pbsouthwood]]: eligible
[[commons:User:Xaosflux]]: eligible
[[commons:User:Draco9904]]: eligible
[[commons:User:Laurent Jerry]]: eligible
[[commons:User:Елена Троянская]]: eligible
[[commons:User:Saeedalijani]]: eligible
[[commons:User:Firstofficer]]: eligible
[[commons:User:Theonlytruth]]: eligible
[[commons:User:Asmeurer]]: eligible
[[commons:User:Barzdonas]]: eligible
[[commons:User:MathKnight]]: eligible
[[commons:User:BarretBonden]]: eligible
[[commons:User:China Crisis]]: eligible
[[commons:User:Mbkv717]]: eligible
[[commons:User:Antony-22]]: eligible
[[commons:User:Eemmeeffe]]: eligible
[[commons:User:عماد زيتوني]]: eligible
[[commons:User:*feridiák]]: eligible
[[commons:User:Yihaa]]: eligible
[[commons:User:Tisfoon]]: eligible
[[commons:User:Mariordo]]: eligible
[[commons:User:Hint000]]: eligible
[[commons:User:Joshualouie711]]: eligible
[[commons:User:Patrik Kunec]]: eligible
[[commons:User:SAİT71]]: eligible
[[commons:User:Tallan]]: eligible
[[commons:User:FriyMan]]: eligible
[[commons:User:Martin Vrut]]: eligible
[[commons:User:Fireattack]]: eligible
[[commons:User:S.K. Gawali]]: eligible
[[commons:User:Cathy Richards]]: eligible
[[commons:User:Peter17]]: eligible
[[commons:User:Divof]]: eligible
[[commons:User:Skepp]]: eligible
[[commons:User:Geher]]: eligible
[[commons:User:Plrk]]: eligible
[[commons:User:Seven twentynine]]: eligible
[[commons:User:Jonie148]]: eligible
[[commons:User:Stigfinnare]]: eligible
[[commons:User:Pierrette13]]: eligible
[[commons:User:Mickaelroux]]: eligible
[[commons:User:MusikAnimal]]: eligible
[[commons:User:4 view 4]]: eligible
[[commons:User:Opencooper]]: eligible
[[commons:User:Kenji]]: eligible
[[commons:User:Samson2005]]: eligible
[[commons:User:Ketrin]]: eligible
[[commons:User:Georgi.sirakov]]: eligible
[[commons:User:Jsamwrites]]: eligible
[[commons:User:Fabiorahamim]]: eligible
[[commons:User:Sverde1]]: eligible
[[commons:User:Dsgn]]: eligible
[[commons:User:TeriEmbrey]]: eligible
[[commons:User:Cyanolinguophile]]: eligible
[[commons:User:Jn045]]: eligible
[[commons:User:Bestoernesto]]: eligible
[[commons:User:Pichpich]]: eligible
[[commons:User:Krupolskiy Anonim]]: eligible
[[commons:User:Paith]]: eligible
[[commons:User:Reade]]: eligible
[[commons:User:VanHelsing.16]]: eligible
[[commons:User:Стефанко1982]]: eligible
[[commons:User:ManfredMann]]: eligible
[[commons:User:C0nanPayne]]: eligible
[[commons:User:Godot13]]: eligible
[[commons:User:Bobamnertiopsis]]: eligible
[[commons:User:Xocolatl]]: eligible
[[commons:User:Nowy15]]: eligible
[[commons:User:Ickle]]: eligible
[[commons:User:Gorivero]]: eligible
[[commons:User:Superbia23]]: eligible
[[commons:User:Okras]]: eligible
[[commons:User:Rodrigogomes2004]]: eligible
[[commons:User:Twkz0731]]: eligible
[[commons:User:Rpotance]]: eligible
[[commons:User:JustAGuyOnWikipedia]]: eligible
[[commons:User:Mikek999]]: eligible
[[commons:User:Afernand74]]: eligible
[[commons:User:Costamagica]]: eligible
[[commons:User:Jvillafruela]]: eligible
[[commons:User:Peter Greenberg]]: eligible
[[commons:User:Vinícius94]]: eligible
[[commons:User:Martyr2566]]: eligible
[[commons:User:GAlexandrova]]: eligible
[[commons:User:Fotoasturias]]: eligible
[[commons:User:Kertek999]]: eligible
[[commons:User:Ungoliant MMDCCLXIV]]: eligible
[[commons:User:Basik07]]: eligible
[[commons:User:Babu]]: eligible
[[commons:User:Kronikarz Gall]]: eligible
[[commons:User:MartinPoulter]]: eligible
[[commons:User:Agent010]]: eligible
[[commons:User:Dalliance]]: eligible
[[commons:User:Rzuwig]]: eligible
[[commons:User:Rreagan007]]: eligible
[[commons:User:MargotThe]]: eligible
[[commons:User:Moheen Reeyad]]: eligible
[[commons:User:Joelnohnn]]: eligible
[[commons:User:Huage.chen]]: eligible
[[commons:User:DENAMAX]]: eligible
[[commons:User:Janayte]]: eligible
[[commons:User:Vitalyb]]: eligible
[[commons:User:Lsanabria]]: eligible
[[commons:User:DrozhkoSerzh]]: eligible
[[commons:User:Khanzadeh]]: eligible
[[commons:User:Eve Teschlemacher]]: eligible
[[commons:User:Jrcourtois]]: eligible
[[commons:User:Dereckson]]: eligible
[[commons:User:Denverjeffrey]]: eligible
[[commons:User:Kertraon]]: eligible
[[commons:User:Derfesl]]: eligible
[[commons:User:ABDO2008.DZ]]: eligible
[[commons:User:OlEnglish]]: eligible
[[commons:User:Puttyhead]]: eligible
[[commons:User:Mramoeba]]: eligible
[[commons:User:Eiad77]]: eligible
[[commons:User:Michael Barera]]: eligible
[[commons:User:Ariaveeg]]: eligible
[[commons:User:DragonSamYU]]: eligible
[[commons:User:Nived 90]]: eligible
[[commons:User:Hgh1993]]: eligible
[[commons:User:Bijaya2043]]: eligible
[[commons:User:Pierpao]]: eligible
[[commons:User:Notafish]]: eligible
[[commons:User:Julian Herzog]]: eligible
[[commons:User:Kingstoken]]: eligible
[[commons:User:Alchemist-hp]]: eligible
[[commons:User:Shishirdasika]]: eligible
[[commons:User:Meyti.ae]]: eligible
[[commons:User:Ivica Vlahović]]: eligible
[[commons:User:TempleM]]: eligible
[[commons:User:Hydro]]: eligible
[[commons:User:דוג'רית]]: eligible
[[commons:User:Jomo]]: eligible
[[commons:User:Samwalton9]]: eligible
[[commons:User:Plogeo]]: eligible
[[commons:User:Fernando Matos Silva e Silva]]: eligible
[[commons:User:^Fabrice^^]]: eligible
[[commons:User:Illustrator]]: eligible
[[commons:User:MAINEiac4434]]: eligible
[[commons:User:Boism]]: eligible
[[commons:User:Gebrelu]]: eligible
[[commons:User:Jiten Dhandha]]: eligible
[[commons:User:Begostas]]: eligible
[[commons:User:Georgios86]]: eligible
[[commons:User:Pawel Dymanski]]: eligible
[[commons:User:AlbertEinstein05]]: eligible
[[commons:User:HybridExplorer]]: eligible
[[commons:User:ZweiZahn]]: eligible
[[commons:User:Leo12555]]: eligible
[[commons:User:Luisbgomezl]]: eligible
[[commons:User:Benrusholme]]: eligible
[[commons:User:Edei]]: eligible
[[commons:User:Koocheki]]: eligible
[[commons:User:JJBers]]: eligible
[[commons:User:Bs.1416]]: eligible
[[commons:User:Ordensherre]]: eligible
[[commons:User:Sahehco]]: eligible
[[commons:User:João Sousa]]: eligible
[[commons:User:GegeZ]]: eligible
[[commons:User:Twofortnights]]: eligible
[[commons:User:E0steven]]: eligible
[[commons:User:Bibliophile]]: eligible
[[commons:User:Gossipguy]]: eligible
[[commons:User:Abu-Dun]]: eligible
[[commons:User:Indeed]]: eligible
[[commons:User:SMasters]]: eligible
[[commons:User:Lina Yab]]: eligible
[[commons:User:Antonius Espertus]]: eligible
[[commons:User:Carturo222]]: eligible
[[commons:User:DrTrumpet]]: eligible
[[commons:User:Hayden Von Feldheim]]: eligible
[[commons:User:Crazy1880]]: eligible
[[commons:User:Miruva]]: eligible
[[commons:User:Spinal83]]: eligible
[[commons:User:KOchstudiO]]: eligible
[[commons:User:Futurix]]: eligible
[[commons:User:Regno di Arendelle]]: eligible
[[commons:User:Ssriram mt]]: eligible
[[commons:User:DavidAnstiss]]: eligible
[[commons:User:OneMember]]: eligible
[[commons:User:TheVovaNik]]: eligible
[[commons:User:Venca24]]: eligible
[[commons:User:Dalek2point3]]: eligible
[[commons:User:MaCleDo]]: eligible
[[commons:User:Smarkflea]]: eligible
[[commons:User:BamLifa]]: eligible
[[commons:User:BlueJaeger]]: eligible
[[commons:User:Joergens.mi]]: eligible
[[commons:User:Miyorineko]]: eligible
[[commons:User:Nesimis]]: eligible
[[commons:User:Director]]: eligible
[[commons:User:Deror avi]]: eligible
[[commons:User:An-Min]]: eligible
[[commons:User:Mahanrahi]]: eligible
[[commons:User:Keithonearth]]: eligible
[[commons:User:Kieprongbuon812]]: eligible
[[commons:User:Zidanie5]]: eligible
[[commons:User:Cnbrb]]: eligible
[[commons:User:Bootingman]]: eligible
[[commons:User:Jennaxel]]: eligible
[[commons:User:Sefp-maru]]: eligible
[[commons:User:Ragesoss]]: eligible
[[commons:User:Znuddel]]: eligible
[[commons:User:Mieczysław Podolski]]: eligible
[[commons:User:Andgy]]: eligible
[[commons:User:RuthVancouver]]: eligible
[[commons:User:Vulcanodong]]: eligible
[[commons:User:ShreCk]]: eligible
[[commons:User:Zupez zeta]]: eligible
[[commons:User:RH Swearengin]]: eligible
[[commons:User:Fontema]]: eligible
[[commons:User:TheGoldenRule]]: eligible
[[commons:User:Leander9999]]: eligible
[[commons:User:Shayshal2]]: eligible
[[commons:User:Nordic Nightfury]]: eligible
[[commons:User:Bark]]: eligible
[[commons:User:AdBo]]: eligible
[[commons:User:CFCF]]: eligible
[[commons:User:Johnny Colt]]: eligible
[[commons:User:Chandravathanaa]]: eligible
[[commons:User:Manne marak]]: eligible
[[commons:User:MissNoya]]: eligible
[[commons:User:Yashaa]]: eligible
[[commons:User:John cema]]: eligible
[[commons:User:U-leo]]: eligible
[[commons:User:Tony Rodi]]: eligible
[[commons:User:Lamprus]]: eligible
[[commons:User:Rayukk]]: eligible
[[commons:User:Aab]]: eligible
[[commons:User:Estopedist1]]: eligible
[[commons:User:Brams]]: eligible
[[commons:User:Micgryga]]: eligible
[[commons:User:Quodvultdeus]]: eligible
[[commons:User:Paravinfo]]: eligible
[[commons:User:Gpc62]]: eligible
[[commons:User:Calliopejen1]]: eligible
[[commons:User:Aw58]]: eligible
[[commons:User:DatGuy]]: eligible
[[commons:User:Angel X]]: eligible
[[commons:User:Miuheo97]]: eligible
[[commons:User:Melquíades]]: eligible
[[commons:User:Sokratees9]]: eligible
[[commons:User:Jnareb]]: eligible
[[commons:User:Faryn2016]]: eligible
[[commons:User:Barbariandeagle]]: eligible
[[commons:User:Elisauer]]: eligible
[[commons:User:Nadiya Li]]: eligible
[[commons:User:Gavreh]]: eligible
[[commons:User:Sg7438]]: eligible
[[commons:User:Axel.Mauruszat]]: eligible
[[commons:User:Jul545454]]: eligible
[[commons:User:Sj]]: eligible
[[commons:User:Tom29739]]: eligible
[[commons:User:Bpierreb]]: eligible
[[commons:User:Anandcv]]: eligible
[[commons:User:DomenikaBo]]: eligible
[[commons:User:George Ho]]: eligible
[[commons:User:Tueftli]]: eligible
[[commons:User:ECanalla]]: eligible
[[commons:User:Clindberg]]: eligible
[[commons:User:Holden15]]: eligible
[[commons:User:Stefanobiondo]]: eligible
ERROR: KeyError: 'merged'
[[commons:User:Jogi don]]: ineligible
[[commons:User:Robin klein]]: eligible
[[commons:User:Amarvudol]]: eligible
[[commons:User:BrunoHP]]: eligible
[[commons:User:Topumym]]: eligible
[[commons:User:Hitman4869]]: eligible
[[commons:User:Canadian Paul]]: eligible
[[commons:User:Zofo]]: eligible
[[commons:User:Calimo]]: eligible
[[commons:User:MC2013]]: eligible
[[commons:User:Target360YT]]: eligible
[[commons:User:Witia]]: eligible
[[commons:User:Myoglobin]]: eligible
[[commons:User:Lafeber]]: eligible
[[commons:User:Fraxinus]]: eligible
[[commons:User:Vplusa]]: eligible