#!/usr/bin/env python3
"""Download MCSR Ranked match data for the Split-Coach import.

Usage:  python mcsr_download.py NAME [COUNT] [ranked|casual|all]
        e.g. python mcsr_download.py Feinberg 100

Creates mcsr_NAME.json in the current folder. Open the Split-Coach page,
expand "Browser blocking the API?" and select that file.
Python 3 standard library only.
"""
import json
import sys
import time
import urllib.error
import urllib.parse
import urllib.request

BASES = ['https://api.mcsrranked.com', 'https://mcsrranked.com/api']
TYPES = {'ranked': '2', 'casual': '1', 'all': ''}
base_idx = 0


def api_get(path):
    global base_idx
    for attempt in range(8):
        req = urllib.request.Request(BASES[base_idx] + path, headers={
            'Accept': 'application/json',
            'User-Agent': 'mcsr-split-coach-downloader/1.0',
        })
        try:
            with urllib.request.urlopen(req, timeout=30) as res:
                body = json.loads(res.read().decode('utf-8'))
        except urllib.error.HTTPError as e:
            if e.code == 429:
                print('  Rate limit reached, waiting 30 seconds ...')
                time.sleep(30)
                continue
            try:
                body = json.loads(e.read().decode('utf-8'))
            except Exception:
                if e.code >= 500 and attempt < 4:
                    time.sleep(2)
                    continue
                raise SystemExit(f'Unexpected response from the API (HTTP {e.code}).')
        except (urllib.error.URLError, TimeoutError) as e:
            if base_idx < len(BASES) - 1:
                base_idx += 1
                continue
            if attempt < 2:
                time.sleep(1)
                continue
            raise SystemExit(f"Can't reach the MCSR API: {e}")
        if body.get('status') != 'success':
            data = body.get('data')
            raise SystemExit(data if isinstance(data, str) else 'API error.')
        return body['data']
    raise SystemExit('Rate limit keeps being hit. Please try again in a few minutes.')


def main():
    args = sys.argv[1:]
    if not args or args[0] in ('-h', '--help'):
        print(__doc__.strip())
        return
    name = args[0]
    count = int(args[1]) if len(args) > 1 else 100
    mode = args[2].lower() if len(args) > 2 else 'ranked'
    if mode not in TYPES:
        raise SystemExit('Mode must be ranked, casual or all.')

    print(f'Looking up {name} ...')
    user = api_get('/users/' + urllib.parse.quote(name))

    matches, before = [], None
    while len(matches) < count:
        n = min(100, count - len(matches))
        q = f"/users/{user['uuid']}/matches?count={n}&excludedecay=true"
        if TYPES[mode]:
            q += '&type=' + TYPES[mode]
        if before:
            q += f'&before={before}'
        page = api_get(q)
        if not page:
            break
        matches.extend(page)
        before = page[-1]['id']
        if len(page) < n:
            break

    details = []
    for i, m in enumerate(matches, 1):
        print(f'\r  Match details {i} / {len(matches)}', end='', flush=True)
        try:
            details.append(api_get(f"/matches/{m['id']}"))
        except SystemExit as e:
            print(f"\n  Skipped match {m['id']}: {e}")
    print()

    out = f"mcsr_{user.get('nickname', name)}.json"
    with open(out, 'w', encoding='utf-8') as f:
        json.dump({'user': user, 'matches': details}, f, ensure_ascii=False)
    print(f'Saved {len(details)} matches to {out}')


if __name__ == '__main__':
    main()
