# -*- coding: utf-8 -*-
"""What the "Ceny AI" dialog shows: the pages' data built from the usage history (wcs/ai/usage_store.py).

No Kodi controls here, only plain data: a page is a set of facts plus rows of text (c1..c5 are the five columns of the
dialog's list). The dialog (DialogAICosts.py) puts them on screen and runs the deleting.
"""
import datetime

from wcs.ai import accounts
from wcs.ai import usage_store as store
from wcs.ai.UsageTracker import cost_parts, format_cost, format_tokens

PERIODS = ('today', 'week', 'month', 'all')
DEFAULT_PERIOD = 'month'
CHART_DAYS = 30
TOP_ENTRIES = 3

# the stored purposes of the calls -> the groups the dialog shows (the id is also the name of its label)
PURPOSE_GROUPS = {
    'millionaire_chat': 'millionaire', 'director_tip': 'tips', 'story_prepare': 'story',
    'quiz': 'quiz', 'actor_quiz': 'quiz', 'director_quiz': 'quiz', 'creator_quiz': 'quiz', 'writer_quiz': 'quiz',
    'text_game': 'text_game', 'game': 'text_game',
    'recommendation': 'recommendation', 'mytv_recommendation': 'recommendation', 'mycinema_recommendation': 'recommendation',
    'channel_name': 'names', 'cinema_name': 'names', store.LEGACY_PURPOSE: 'legacy',
}
OTHER_GROUP = 'other'
MILLIONAIRE_SESSION = 's:millionaire'


def purpose_group(purpose):
    return PURPOSE_GROUPS.get(purpose, OTHER_GROUP)


def period_range(period, today=None):
    """(first day, last day) of a period as YYYY-MM-DD; ('all') leaves both open."""
    today = today or datetime.date.today()
    if period == 'today':
        return today.isoformat(), today.isoformat()
    if period == 'week':
        return (today - datetime.timedelta(days=6)).isoformat(), today.isoformat()
    if period == 'month':
        return today.replace(day=1).isoformat(), today.isoformat()
    return None, None


def when(stamp):
    """'2026-10-06T22:02:27' -> '6. 10. 22:02'."""
    try:
        moment = datetime.datetime.fromisoformat(stamp)
    except ValueError:
        return stamp
    return '{}. {}. {:02d}:{:02d}'.format(moment.day, moment.month, moment.hour, moment.minute)


def tokens_text(row):
    """'in / cached / out' tokens of a row, the way the dialog shows them."""
    return '{} / {} / {}'.format(format_tokens(row['input_tokens']), format_tokens(row['cached_tokens']),
                                 format_tokens(row['output_tokens']))


def _share(value, total):
    return int(round(100.0 * value / total)) if total > 0 else 0


STRING_IDS = {
    'purpose_story': 35401,
    'title': 32800, 'overview': 32801, 'models': 32802, 'purposes': 32803, 'history': 32804,
    'today': 32805, 'week': 32806, 'month': 32807, 'all': 32808, 'delete': 32809, 'export': 32810, 'close': 32811,
    'cost': 32812, 'calls': 32813, 'tokens': 32814, 'savings': 32815, 'chart': 32816, 'top': 32817,
    'per_call_label': 32818, 'per_game_label': 32819, 'today_label': 32820, 'month_label': 32821, 'overall_label': 32822,
    'purpose_millionaire': 32830, 'purpose_tips': 32831, 'purpose_quiz': 32832, 'purpose_text_game': 32833,
    'purpose_recommendation': 32834, 'purpose_names': 32835, 'purpose_legacy': 32836, 'purpose_other': 32837,
    'errors_note': 32840, 'savings_note': 32841, 'per_call': 32842, 'failed': 32843, 'per_game': 32844,
    'tokens_legend': 32879,
    'col_model': 32845, 'col_purpose': 32846, 'col_purpose_tokens': 32880, 'col_entry': 32847, 'col_time': 32848, 'col_tokens': 32849,
    'col_calls': 32850, 'col_share': 32851, 'col_when': 32852, 'col_response': 32853, 'col_cost': 32854,
    'delete_title': 32860, 'delete_entry': 32861, 'delete_call': 32862, 'delete_day': 32863, 'delete_month': 32864,
    'delete_provider': 32865, 'delete_all': 32866, 'delete_confirm': 32867, 'deleted': 32868, 'nothing': 32869,
    'exported': 32870, 'empty': 32871, 'delete_short': 32872, 'hint_arrows': 32873, 'hint_select': 32874,
    'hint_confirm': 32875, 'hint_back': 32876, 'hint_return': 32877, 'rate': 32878,
}


def load_strings(addon):
    return {name: addon.getLocalizedString(string_id) for name, string_id in STRING_IDS.items()}


class Texts:
    """The words the pages use: the localized strings (load_strings) and the user's currency setting."""

    def __init__(self, strings, addon=None):
        self.s = strings
        self.addon = addon

    def money(self, cost):
        return format_cost(cost, self.addon)

    def pair(self, cost):
        """(main, other) text of a cost for a big number and the line under it."""
        usd, czk = cost_parts(cost, self.addon)
        return (usd or czk), (czk if usd else '')

    def calls(self, count):
        return '{}×'.format(int(count))

    def purpose(self, purpose):
        return self.s['purpose_' + purpose_group(purpose)]


# ---- pages
def overview(texts, period, today=None):
    since, until = period_range(period, today)
    total = store.totals(since, until)
    today = today or datetime.date.today()
    month_start = today.replace(day=1).isoformat()
    entries = store.sessions(since, until, limit=5000)
    games = [entry for entry in entries if entry['key'].startswith(MILLIONAIRE_SESSION)]
    first = (today - datetime.timedelta(days=CHART_DAYS - 1)).isoformat()
    days = store.per_day(first, today.isoformat())
    cost, cost_other = texts.pair(total['cost'])
    savings, savings_other = texts.pair(total['savings'])
    per_call = texts.pair(total['cost'] / total['requests'])[0] if total['requests'] else ''
    per_game = texts.pair(sum(g['cost'] for g in games) / len(games))[0] if games else ''
    cached_share = _share(total['cached_tokens'], total['input_tokens'] + total['cached_tokens'])
    return {
        'cost': cost, 'cost_note': cost_other, 'cost_note2': texts.s['per_game'].format(per_game) if per_game else '',
        'calls': str(int(total['requests'])), 'calls_note': texts.s['per_call'].format(per_call) if per_call else '',
        'calls_note2': texts.s['errors_note'].format(int(total['errors'])) if total['errors'] else '',
        'tokens': format_tokens(total['input_tokens'] + total['cached_tokens'] + total['output_tokens']),
        'tokens_note': '/'.join(format_tokens(total[key]) for key in ('input_tokens', 'cached_tokens', 'output_tokens')),
        'tokens_note2': texts.s['tokens_legend'],
        'savings': savings, 'savings_note': savings_other,
        'savings_note2': texts.s['savings_note'].format(cached_share) if total['cached_tokens'] else '',
        'today': texts.pair(store.totals(today.isoformat(), today.isoformat())['cost'])[0],
        'month': texts.pair(store.totals(month_start, today.isoformat())['cost'])[0],
        'overall': texts.pair(store.totals()['cost'])[0],
        'chart': [{'day': d['day'], 'cost': d['cost']} for d in days],
        'chart_max': texts.pair(max([d['cost'] for d in days] or [0]))[0],
        'rows': [_entry_row(texts, entry) for entry in sorted(entries, key=lambda e: e['cost'], reverse=True)[:TOP_ENTRIES]],
    }


def _entry_row(texts, entry):
    name = entry['title'] or texts.purpose(entry['purpose'])
    return {'kind': 'entry', 'key': entry['key'], 'c1': name,
            'c2': '{}  ·  {}'.format(texts.purpose(entry['purpose']), entry['model']) if entry['title'] else entry['model'],
            'c3': texts.calls(entry['requests']), 'c4': when(entry['last_ts']), 'c5': texts.money(entry['cost']),
            'error': bool(entry['errors']), 'day': entry['last_ts'][:10], 'provider': entry['provider']}


def models(texts, period):
    since, until = period_range(period)
    rows = store.per_model(since, until)
    total = sum(row['cost'] for row in rows)
    result = []
    for row in rows:
        provider_name = accounts.PROVIDERS.get(row['provider'], (row['provider'],))[0]
        average = texts.pair(row['cost'] / row['requests'])[0] if row['requests'] else texts.pair(0)[0]
        result.append({'kind': 'model', 'key': '', 'c1': row['model'],
                       'c2': '{}  ·  {}  ·  {}'.format(provider_name, tokens_text(row), 'Ø {}'.format(average)),
                       'c3': texts.calls(row['requests']), 'c4': '{} %'.format(_share(row['cost'], total)),
                       'c5': texts.money(row['cost']), 'provider': row['provider'], 'share': _share(row['cost'], total),
                       'error': bool(row['errors'])})
    return result


def purposes(texts, period):
    since, until = period_range(period)
    merged = {}
    for row in store.per_purpose(since, until):
        group = merged.setdefault(purpose_group(row['purpose']), dict(requests=0, errors=0, cost=0.0, savings=0.0,
                                                                      input_tokens=0, cached_tokens=0, output_tokens=0))
        for key in group:
            group[key] += row[key]
    total = sum(group['cost'] for group in merged.values())
    rows = []
    for name, group in sorted(merged.items(), key=lambda item: item[1]['cost'], reverse=True):
        rows.append({'kind': 'purpose', 'key': '', 'c1': texts.s['purpose_' + name], 'c2': tokens_text(group),
                     'c3': texts.calls(group['requests']), 'c4': '{} %'.format(_share(group['cost'], total)),
                     'c5': texts.money(group['cost']), 'share': _share(group['cost'], total), 'error': bool(group['errors'])})
    return rows


def history(texts, period):
    since, until = period_range(period)
    return [_entry_row(texts, entry) for entry in store.sessions(since, until)]


def detail(texts, key):
    """The calls of one history entry (a game or a single call)."""
    rows = []
    for call in store.calls_of(key):
        failed = call['status'] == 'error'
        rows.append({'kind': 'call', 'key': 'k:{}'.format(call['id']), 'call_id': call['id'],
                     'c1': when(call['ts']),
                     'c2': call['error'] if failed else tokens_text(call),
                     'c3': '{:.1f} s'.format(call['latency_ms'] / 1000.0) if call['latency_ms'] else '',
                     'c4': texts.purpose(call['purpose']) if not failed else texts.s['failed'],
                     'c5': texts.money(call['cost']), 'error': failed, 'day': call['day'], 'provider': call['provider']})
    return rows
