# -*- coding: utf-8 -*-
"""LLM judge of a Pro tebe snapshot (docs/plan/pro-tebe/010 §8): an independent model rates every row as a picky
Czech viewer would and lists bad picks, so tuning has a signal beyond eyeballing. Costs API credit.

    python3 scripts/foryou_harness/judge.py [snapshot.json|--live] [--provider openai|anthropic] [--model M]
                                            [--effort medium] [--mode all|movie|tv]

Default judge: OpenAI gpt-6-luna, reasoning effort medium. Keys from the addon settings (never printed);
--live judges the snapshot Kodi uses now (library.db); writes out/judge_<time>.json.
"""
import argparse
import json
import os
import sys
import time
import urllib.error
import urllib.request
import xml.etree.ElementTree as ET

HERE = os.path.dirname(os.path.abspath(__file__))
OUT = os.path.join(HERE, 'out')
sys.path.insert(0, HERE)
from foryou_harness import reason_text, row_title  # noqa: E402

SETTINGS = os.path.expanduser('~/Library/Application Support/Kodi/userdata/addon_data/plugin.video.milionar/settings.xml')

PROMPT = """Jsi přísný kurátor doporučovacího systému typu Netflix / Apple TV pro českou domácnost.
Níže je historie domácnosti (co viděla / má v seznamu / ohodnotila) a stránka „Pro tebe", kterou systém vygeneroval
(bez AI, jen z TMDb). Každá položka: název, rok, typ (film/seriál), % shody, důvod.

Dnes je {today}. Všechny tituly na stránce jsou už vydané a systém u každého ověřil, že jde přehrát
s uvedeným jazykem (CZ dabing / CZ titulky / SK dabing); rok 2026 tedy není chyba. Top 10 v ČR je záměrně
nepersonalizovaný žebříček (jako u Netflixu); hodnoť, jestli je to rozumný žebříček pro Česko.
Ohodnoť stránku očima náročného diváka z této domácnosti. Odpověz v tomto tvaru:
{{"overall": 1-10,
  "rows": [{{"row": "<název řady>", "score": 1-10, "comment": "<1 věta>"}}],
  "bad_picks": [{{"title": "<název>", "row": "<řada>", "why": "<krátce>"}}],
  "missing": ["<titul, který by tu jasně měl být a chybí>"],
  "fixes": ["<konkrétní úprava algoritmu, max 6 bodů, seřazeno podle dopadu>"]}}

Historie domácnosti:
{history}

Stránka (režim {mode}, denní doba {slot}):
{page}
"""


def api_key(name='anthropic_api_key'):
    for node in ET.parse(SETTINGS).getroot().iter('setting'):
        if node.get('id') == name:
            return node.text or ''
    return ''


LANGS = {'cz_dub': 'CZ dabing', 'cz_sub': 'CZ titulky', 'sk_dub': 'SK dabing'}
LIVE_DB = os.path.expanduser('~/Library/Application Support/Kodi/userdata/addon_data/plugin.video.milionar/library.db')
SCHEMA_HINT = (' JSON objekt s klíči overall (1-10), rows [{row, score, comment}], bad_picks [{title, row, why}],'
               ' missing [str], fixes [str].')


def ask_openai(prompt, model, effort):
    """Responses API (gpt-6-luna, reasoning effort), JSON output."""
    body = {'model': model, 'input': [{'type': 'message', 'role': 'user', 'content': prompt + SCHEMA_HINT}],
            'reasoning': {'effort': effort}, 'text': {'verbosity': 'low', 'format': {'type': 'json_object'}},
            'max_output_tokens': 16000}
    request = urllib.request.Request('https://api.openai.com/v1/responses', data=json.dumps(body).encode('utf-8'),
                                     headers={'Authorization': 'Bearer ' + api_key('openai_api_key'),
                                              'content-type': 'application/json'})
    try:
        answer = json.load(urllib.request.urlopen(request, timeout=600))
    except urllib.error.HTTPError as exc:
        print('API error', exc.code, exc.read().decode('utf-8', 'replace')[:500])
        raise SystemExit(1)
    text = ''
    for item in answer.get('output') or []:
        if item.get('type') == 'message':
            text = ''.join(part.get('text', '') for part in item.get('content') or [] if isinstance(part, dict))
            break
    usage = answer.get('usage') or {}
    print('usage: in {} / out {} tokens'.format(usage.get('input_tokens'), usage.get('output_tokens')))
    return json.loads(text)


def describe(snapshot, mode):
    history = '\n'.join('- {} [{}] {}'.format(s['title'], s['kind'], 'film' if s['key'].startswith('movie') else 'seriál')
                        for s in snapshot['seeds'])
    lines = []
    for row in snapshot['modes'][mode]:
        lines.append('\n## ' + row_title(snapshot, row))
        for n, key in enumerate(row['items']):
            it = snapshot['items'][key]
            reason = row.get('reason') or it['reason']
            lines.append('{}. {} ({}, {}) {} · {}{}'.format(n + 1, it['title'], it['year'],
                                                         'film' if it['media'] == 'movie' else 'seriál',
                                                         'TOP {}'.format(n + 1) if row['kind'] == 'top10'
                                                         else '{}%'.format(it['match']),
                                                         reason_text(snapshot, reason),
                                                         ' · ' + LANGS[it['lang']] if it.get('lang') in LANGS else ''))
    return history, '\n'.join(lines)


def ask_anthropic(prompt, model):
    schema = {'type': 'object', 'required': ['overall', 'rows', 'bad_picks', 'missing', 'fixes'], 'properties': {
        'overall': {'type': 'integer'},
        'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {
            'row': {'type': 'string'}, 'score': {'type': 'integer'}, 'comment': {'type': 'string'}}}},
        'bad_picks': {'type': 'array', 'items': {'type': 'object', 'properties': {
            'title': {'type': 'string'}, 'row': {'type': 'string'}, 'why': {'type': 'string'}}}},
        'missing': {'type': 'array', 'items': {'type': 'string'}},
        'fixes': {'type': 'array', 'items': {'type': 'string'}}}}
    body = {'model': model, 'max_tokens': 6000,
            'tools': [{'name': 'verdict', 'description': 'Hodnocení stránky Pro tebe.', 'input_schema': schema}],
            'tool_choice': {'type': 'auto'}, 'messages': [{'role': 'user', 'content': prompt}]}
    request = urllib.request.Request('https://api.anthropic.com/v1/messages', data=json.dumps(body).encode('utf-8'),
                                     headers={'x-api-key': api_key(), 'anthropic-version': '2023-06-01',
                                              'content-type': 'application/json'})
    try:
        answer = json.load(urllib.request.urlopen(request, timeout=300))
    except urllib.error.HTTPError as exc:
        print('API error', exc.code, exc.read().decode('utf-8', 'replace')[:500])
        raise SystemExit(1)
    return next(b['input'] for b in answer.get('content') or [] if b.get('type') == 'tool_use')


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('snapshot', nargs='?')
    parser.add_argument('--live', action='store_true', help='the snapshot Kodi shows now')
    parser.add_argument('--provider', choices=['openai', 'anthropic'], default='openai')
    parser.add_argument('--model', help='default: gpt-6-luna (openai) / claude-opus-5-5 (anthropic)')
    parser.add_argument('--effort', default='medium', help='OpenAI reasoning effort')
    parser.add_argument('--mode', default='all')
    args = parser.parse_args()
    if args.live:
        import sqlite3
        row = sqlite3.connect('file:{}?mode=ro'.format(LIVE_DB), uri=True).execute(
            "SELECT json FROM meta WHERE key='foryou:snapshot'").fetchone()
        snapshot, path = json.loads(row[0]), 'live'
    else:
        path = args.snapshot or os.path.join(OUT, sorted(f for f in os.listdir(OUT) if f.startswith('snapshot_'))[-1])
        snapshot = json.load(open(path, encoding='utf-8'))
    history, page = describe(snapshot, args.mode)
    prompt = PROMPT.format(history=history, page=page, mode=args.mode, slot=snapshot['slot'], today=snapshot['day'])
    if args.provider == 'openai':
        verdict = ask_openai(prompt, args.model or 'gpt-6-luna', args.effort)
    else:
        verdict = ask_anthropic(prompt, args.model or 'claude-opus-5-5')
    os.makedirs(OUT, exist_ok=True)
    target = os.path.join(OUT, 'judge_{}.json'.format(time.strftime('%Y%m%d_%H%M%S')))
    json.dump({'snapshot': os.path.basename(path), 'provider': args.provider, 'model': args.model, 'verdict': verdict}, open(target, 'w'),
              ensure_ascii=False, indent=1)
    print('overall', verdict.get('overall'))
    for row in verdict.get('rows') or []:
        print('  {:>2}  {:<34} {}'.format(row.get('score'), row.get('row', '')[:34], row.get('comment', '')))
    print('bad picks:', '; '.join('{} ({})'.format(b['title'], b.get('why', '')) for b in verdict.get('bad_picks') or []))
    print('missing:', ', '.join(verdict.get('missing') or []))
    print('fixes:')
    for fix in verdict.get('fixes') or []:
        print('  -', fix)
    print('->', os.path.relpath(target))


if __name__ == '__main__':
    main()
