# -*- coding: utf-8 -*-
"""Pure rules of the library (docs/plan/milionar-library/040 §3, §6): no Kodi, no store, fully unit-tested."""

DEFAULT_RESUME_MIN_SECONDS = 180
DEFAULT_WATCHED_PERCENT = 90
RESUME_TOLERANCE_S = 1.5


def effective_total(total, runtime_seconds):
    """Player total time, or the TMDb runtime when the player reports 0 (some streams)."""
    return float(total) if total and total > 0 else float(runtime_seconds or 0)


def outcome(position, total, ended, min_seconds=DEFAULT_RESUME_MIN_SECONDS, watched_percent=DEFAULT_WATCHED_PERCENT):
    """What a stop / end does to the stored state.

    'short'   - position below the resume threshold: nothing is saved (a play that ended naturally below it
                is still 'short' - a trailer-length clip is not a watched film);
    'watched' - position >= watched_percent of total, or the playback ended naturally past the threshold;
    'resume'  - in progress.
    """
    if position < min_seconds:
        return 'short'
    if ended:
        return 'watched'
    if total and total > 0 and (position / total) * 100.0 >= watched_percent:
        return 'watched'
    return 'resume'


def reconcile(ours, kodi, mirrored):
    """Decide whether Kodi's current record carries a user change that must be adopted (040 §6).

    ours     {'last_played_at'}                      what the addon stored last
    kodi     {'playcount', 'resume_pos'}             Kodi's record for the canonical URL now
    mirrored {'playcount', 'resume_pos', 'at'}       what the addon wrote into Kodi last, or None

    Returns None (nothing to adopt) or {'playcount', 'resume_pos'} to apply.
    A difference is a user change made in Kodi unless the addon has newer data than its last mirror
    (a play ended after the mirror: Kodi's own stop-time bookmark is older than ours and is ignored;
    the addon re-mirrors instead).
    """
    if not mirrored or mirrored.get('at') is None:
        return None
    same_count = int(kodi.get('playcount') or 0) == int(mirrored.get('playcount') or 0)
    same_pos = abs(float(kodi.get('resume_pos') or 0) - float(mirrored.get('resume_pos') or 0)) <= RESUME_TOLERANCE_S
    if same_count and same_pos:
        return None
    if (ours.get('last_played_at') or 0) > mirrored['at']:
        return None
    return {'playcount': int(kodi.get('playcount') or 0), 'resume_pos': float(kodi.get('resume_pos') or 0)}


def np_matches(np, playing_file, now, max_age_s=20):
    """Does the now-playing contract belong to the file Kodi started? Exact stream URL match; failing that a
    fresh contract is accepted only while the player has not reported a canonical plugin URL."""
    if not np or not np.get('stream_url'):
        return False
    if playing_file and playing_file == np['stream_url']:
        return True
    return bool(np.get('ts')) and (now - np['ts']) <= max_age_s and not (playing_file or '').startswith('plugin://')
