# -*- coding: utf-8 -*-
"""Service refresher of TMDb data for tracked series (docs/plan/milionar-library/050 §1).

Every series in My series or with watch activity gets its `tv:` and season data refreshed once it is stale (12 h
while the show runs), so a new episode's air date and a newly announced episode are known without the user opening
the series. Never runs while a video plays; one series at a time.
"""
import time

import xbmc

from wcs.library2 import meta, store, tmdb

CHECK_EVERY_S = 1800
_attempted = {}


def _order(ids, media):
    scope = store.db_path()
    return sorted(ids, key=lambda ident: _attempted.get((scope, media, ident), 0))


def _attempt(media, ident):
    _attempted[(store.db_path(), media, ident)] = time.monotonic()


def refresh_movies_due(now=None, fetch=None, limit=5):
    conn = store.connect()
    try:
        ids = [r[0] for r in conn.execute("SELECT tmdb_id FROM titles WHERE media_type='movie' "
                                         "AND (in_list=1 OR last_activity_at IS NOT NULL)")]
    finally:
        conn.close()
    snapshots = meta.get_many_status((meta.key_movie(i) for i in ids), now=now)
    due = [i for i in ids if snapshots.get(meta.key_movie(i), (None, True))[1]]
    for ident in _order(due, 'movie')[:limit]:
        if xbmc.getCondVisibility('Player.HasVideo'):
            return
        try:
            _attempt('movie', ident)
            tmdb.refresh_movie(ident, fetch)
        except Exception as exc:
            xbmc.log('[Milionář Library] movie refresh {}: {}'.format(ident, type(exc).__name__), xbmc.LOGWARNING)


def tracked_series_ids():
    conn = store.connect()
    try:
        rows = conn.execute("SELECT tmdb_id FROM titles WHERE media_type='tv' AND (in_list=1 OR last_activity_at IS NOT NULL)").fetchall()
    finally:
        conn.close()
    return [r['tmdb_id'] for r in rows]


def due_series(now=None):
    """Missing/stale shows or incomplete season coverage; read metadata in bulk."""
    due = []
    ids = tracked_series_ids()
    shows = meta.get_many_status((meta.key_tv(show_id) for show_id in ids), now=now)
    season_keys = set()
    for key, (data, _stale) in shows.items():
        show_id = int(key.split(':')[1])
        season_keys.update(meta.key_season(show_id, s['season_number'])
                           for s in data.get('seasons') or [] if int(s.get('season_number') or 0) > 0)
    seasons = meta.get_many_status(season_keys, now=now)
    for show_id in ids:
        data, stale = shows.get(meta.key_tv(show_id), (None, True))
        incomplete = data is None or 'seasons' not in data
        if not incomplete:
            for s in data.get('seasons') or []:
                number = int(s.get('season_number') or 0)
                if number <= 0:
                    continue
                cached, expired = seasons.get(meta.key_season(show_id, number), (None, True))
                if expired or not cached or 'episodes' not in cached or len(cached['episodes']) < int(s.get('episode_count') or 0):
                    incomplete = True
                    break
        if stale or incomplete:
            due.append(show_id)
    return due


def refresh_due(now=None, fetch=None, playing=lambda: xbmc.getCondVisibility('Player.HasVideo'), limit=5):
    """Refresh up to `limit` due series; returns the ids refreshed."""
    done = []
    for attempt, show_id in enumerate(_order(due_series(now), 'tv')):
        if playing() or attempt >= limit:
            break
        try:
            _attempt('tv', show_id)
            if tmdb.refresh_show(show_id, fetch):
                done.append(show_id)
        except Exception as exc:
            xbmc.log('[Milionář Library] refresh {} failed: {}: {}'.format(show_id, type(exc).__name__, exc), xbmc.LOGWARNING)
    return done


def loop(monitor):
    if monitor.waitForAbort(60):        # let Kodi start before any network work
        return
    while not monitor.abortRequested():
        try:
            refresh_movies_due()
            done = refresh_due()
            if done:
                xbmc.log('[Milionář Library] refreshed series {}'.format(done), xbmc.LOGINFO)
        except Exception as exc:
            xbmc.log('[Milionář Library] refresher failed: {}'.format(exc), xbmc.LOGWARNING)
        if monitor.waitForAbort(CHECK_EVERY_S):
            break
