# -*- coding: utf-8 -*-
"""Unit tests: the pages of the "Ceny AI" dialog (wcs/ai/usage_view.py) on a temporary usage history."""
import datetime
import os
import sys
import tempfile
import unittest

HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
import stubs  # noqa: E402

stubs.install()

from wcs.ai import UsageTracker as tracker  # noqa: E402
from wcs.ai import usage_store as store  # noqa: E402
from wcs.ai import usage_view as view  # noqa: E402

D = datetime.datetime
TODAY = datetime.date(2026, 10, 7)
STRINGS = {name: name for name in view.STRING_IDS}
STRINGS.update(errors_note='{} failed', savings_note='{} % cache', per_call='avg {}', per_game='game {}',
               purpose_millionaire='Millionaire', purpose_tips='Tips', purpose_quiz='Quizzes', purpose_other='Other')


class Addon:
    settings = {'ai_cost_currency': '0'}                 # USD only keeps the expectations short

    def getSetting(self, key):
        return self.settings.get(key, '')


def record(**kwargs):
    values = dict(provider='openai', model='gpt-6-luna', purpose='millionaire_chat', input_tokens=100, cached_tokens=900,
                  output_tokens=50, input_cost=0.1, cached_cost=0.01, output_cost=0.2, savings=0.05)
    values.update(kwargs)
    return store.record_call(**values)


class ViewTests(unittest.TestCase):
    def setUp(self):
        store.set_path(os.path.join(tempfile.mkdtemp(prefix='milionar-view-'), 'ai_usage.db'))
        self.texts = view.Texts(STRINGS, Addon())
        record(now=D(2026, 10, 7, 12), session_id='millionaire_a', title='Matrix')
        record(now=D(2026, 10, 7, 12, 5), session_id='millionaire_a', title='Matrix')
        record(now=D(2026, 10, 6, 9), purpose='quiz', provider='anthropic', model='claude-sonnet-5-5')
        record(now=D(2026, 9, 20, 9), purpose='director_tip')
        record(now=D(2026, 10, 7, 13), status='error', error='HTTP 529', input_tokens=0, cached_tokens=0, output_tokens=0,
               input_cost=0, cached_cost=0, output_cost=0, savings=0)

    def test_periods(self):
        self.assertEqual(view.period_range('today', TODAY), ('2026-10-07', '2026-10-07'))
        self.assertEqual(view.period_range('week', TODAY), ('2026-10-01', '2026-10-07'))
        self.assertEqual(view.period_range('month', TODAY), ('2026-10-01', '2026-10-07'))
        self.assertEqual(view.period_range('all', TODAY), (None, None))

    def test_overview_of_the_whole_history(self):
        data = view.overview(self.texts, 'all', TODAY)
        self.assertEqual(data['calls'], '5')
        self.assertEqual(data['cost'], '$1.24')
        self.assertEqual(data['calls_note2'], '1 failed')
        self.assertEqual(data['tokens'], '4.2K')
        self.assertEqual(data['savings_note2'], '90 % cache')
        self.assertEqual(data['cost_note2'], 'game $0.620')                       # the Millionaire game: one session
        self.assertEqual(data['today'], '$0.620')
        self.assertEqual(len(data['chart']), view.CHART_DAYS)
        self.assertAlmostEqual(data['chart'][-1]['cost'], 0.62)                   # today: the game
        self.assertAlmostEqual(data['chart'][-2]['cost'], 0.31)                   # yesterday: the quiz
        self.assertEqual(len(data['rows']), view.TOP_ENTRIES)
        self.assertEqual(data['rows'][0]['c1'], 'Matrix')                         # the dearest entry comes first

    def test_overview_of_an_empty_history(self):
        store.delete_all()
        data = view.overview(self.texts, 'month', TODAY)
        self.assertEqual((data['calls'], data['cost'], data['rows']), ('0', '$0', []))
        self.assertEqual(data['cost_note2'], '')

    def test_models_purposes_and_history_rows(self):
        models = view.models(self.texts, 'all')
        self.assertEqual([row['c1'] for row in models], ['gpt-6-luna', 'claude-sonnet-5-5'])
        self.assertEqual(models[0]['provider'], 'openai')
        self.assertEqual(models[0]['share'] + models[1]['share'], 100)
        purposes = {row['c1']: row['c3'] for row in view.purposes(self.texts, 'all')}
        self.assertEqual(purposes, {'Millionaire': '3×', 'Quizzes': '1×', 'Tips': '1×'})
        history = view.history(self.texts, 'all')
        self.assertEqual(len(history), 4)                                         # one game + three single calls
        game = next(row for row in history if row['key'].startswith('s:'))
        self.assertEqual((game['c1'], game['c3']), ('Matrix', '2×'))
        self.assertTrue(any(row['error'] for row in history))
        self.assertEqual({e['last_ts'][:10] for e in store.sessions('2026-10-07', '2026-10-07')}, {'2026-10-07'})

    def test_the_calls_of_an_entry(self):
        calls = view.detail(self.texts, 's:millionaire_a')
        self.assertEqual(len(calls), 2)
        self.assertEqual(calls[0]['c1'], '7. 10. 12:00')
        self.assertEqual(calls[0]['c2'], '100 / 900 / 50')
        failed = view.detail(self.texts, next(row['key'] for row in view.history(self.texts, 'all') if row['error']))[0]
        self.assertEqual((failed['error'], failed['c2'], failed['c4']), (True, 'HTTP 529', 'failed'))

    def test_every_purpose_the_addon_records_has_a_group_and_every_group_a_string(self):
        for purpose in ('millionaire_chat', 'director_tip', 'quiz', 'text_game', 'recommendation', 'mytv_recommendation',
                        'mycinema_recommendation', 'channel_name', 'cinema_name', 'legacy', 'actor_quiz', 'game'):
            self.assertNotEqual(view.purpose_group(purpose), view.OTHER_GROUP, purpose)
        for group in set(view.PURPOSE_GROUPS.values()) | {view.OTHER_GROUP}:
            self.assertIn('purpose_' + group, view.STRING_IDS)
        self.assertEqual(view.purpose_group('something new'), view.OTHER_GROUP)

    def test_every_string_the_dialog_uses_exists_in_all_languages(self):
        import re
        for lang in ('cs_cz', 'en_gb', 'sk_sk'):
            with open(os.path.join(stubs.ADDON_DIR, 'resources', 'language', 'resource.language.' + lang, 'strings.po'),
                      encoding='utf-8') as handle:
                text = handle.read()
            ids = set(int(x) for x in re.findall(r'msgctxt "#(\d+)"', text))
            self.assertEqual([name for name, number in view.STRING_IDS.items() if number not in ids], [], lang)
            self.assertIn(32800, ids)


if __name__ == '__main__':
    unittest.main()
