# -*- coding: utf-8 -*-
"""Native Kodi list-container live guide; one template reused for all channels."""
import os, sys, time
import xbmc, xbmcgui, xbmcaddon
from default import (GROUPS, read_cache, update_cache, schedule, clock,
                     preferences, channel_key, save_preference, endpoint)

ADDON = xbmcaddon.Addon(id='plugin.video.kodiflix.live')
ROOT = ADDON.getAddonInfo('path')

def image_source(*values):
    for value in values:
        if not isinstance(value, str):
            continue
        value = value.strip()
        if value.startswith(('https://', 'http://', 'image://', 'special://')):
            return value
    return ''


def clip_text(value, limit):
    value = ' '.join(str(value or '').split())
    return value if len(value) <= limit else value[:max(0,limit-1)].rstrip() + '…'


class LiveWindow(xbmcgui.WindowXMLDialog):
    def __init__(self, *args, **kwargs):
        self.category = kwargs.pop('category')
        self.channels = []
        self.pending = None
        self.last_position = kwargs.pop('position', 0)
        super().__init__(*args, **kwargs)

    def onInit(self):
        self.getControl(100).setLabel(dict(GROUPS).get(self.category, 'Live TV'))
        data = read_cache(self.category)
        if data is None:
            self.getControl(101).setLabel('EPG cache is being prepared. Please reopen shortly.')
            return
        self.getControl(101).setLabel('')
        now = int(time.time())
        prefs = preferences()
        items = []
        for channel in data.get('channels', []):
            sources = channel.get('sources') or []
            if not sources:
                continue
            playing, upcoming = schedule(channel, now)
            label = channel.get('label') or 'Channel'
            item = xbmcgui.ListItem(label=label)
            item.setProperty('channel', clip_text(label, 49))
            item.setProperty('now', clip_text((playing or {}).get('title') or 'Schedule unavailable', 48))
            item.setProperty('next', clip_text((upcoming or {}).get('title') or 'Schedule unavailable', 42))
            item.setProperty('nexttime', clock(upcoming['start_ts']) if upcoming else '')
            item.setProperty('logo', image_source(channel.get('logo'), channel.get('icon'), channel.get('thumb')))
            item.setProperty('artwork', image_source((playing or {}).get('icon'), (playing or {}).get('artwork'), (playing or {}).get('thumb'), (playing or {}).get('image')))
            item.setArt({'icon': item.getProperty('logo'), 'thumb': item.getProperty('artwork')})
            description = ((playing or {}).get('description') or '').replace('\\n', ' ').strip()
            item.setProperty('description', clip_text(description, 230))
            if playing:
                duration = max(1, int(playing['end_ts'])-int(playing['start_ts']))
                item.setProperty('progress', str(max(0,min(100,int((int(playing['end_ts'])-now)*100/duration)))))
                item.setProperty('remaining_bar', 'special://home/addons/plugin.video.kodiflix.live/resources/media/live_remaining_%03d.png' % max(0,min(100,round((int(playing['end_ts'])-now)*100/duration))))
                item.setProperty('remaining', str(max(0,(int(playing['end_ts'])-now+59)//60))+' min left')
            else:
                item.setProperty('progress','0')
                item.setProperty('remaining_bar','special://home/addons/plugin.video.kodiflix.live/resources/media/live_remaining_000.png')
                item.setProperty('remaining','')
            self.channels.append(channel)
            items.append(item)
        control = self.getControl(200)
        control.addItems(items)
        if items:
            control.selectItem(min(self.last_position, len(items)-1))
            self.setFocus(control)

    def onClick(self, controlId):
        if controlId == 200:
            index = self.getControl(200).getSelectedPosition()
            if 0 <= index < len(self.channels):
                self.pending = ('play', index)
                self.last_position = index
                self.close()

    def onAction(self, action):
        aid = action.getId()
        if aid in (9, 10, 92, 216):
            self.close()
            return
        if aid in (11, 117):
            index = self.getControl(200).getSelectedPosition()
            if 0 <= index < len(self.channels):
                self.last_position = index
                self.pending = ('info' if aid == 11 else 'sources', index)
                self.close()

def run(category):
    if read_cache(category) is None:
        try:
            update_cache(category)
        except Exception as exc:
            xbmc.log('KodiFlix Live cache initialization: '+repr(exc), xbmc.LOGERROR)
            xbmcgui.Dialog().notification('KodiFlix Live', 'Could not load EPG: '+str(exc)[:80], xbmcgui.NOTIFICATION_ERROR, 5000)
            return
    position = 0
    while not xbmc.Monitor().abortRequested():
        win = LiveWindow('Stacked.xml', ROOT, 'Default', '1080i', category=category, position=position)
        win.doModal()
        pending, position = win.pending, win.last_position
        channels = win.channels
        del win
        if not pending:
            break
        action, index = pending
        channel = channels[index]
        sources = channel.get('sources') or []
        if action == 'info':
            playing, upcoming = schedule(channel, int(time.time()))
            msg = 'NOW: {}\n\nNEXT: {} {}\n\n{}'.format(
                (playing or {}).get('title','Unknown'),
                clock(upcoming['start_ts']) if upcoming else '',
                (upcoming or {}).get('title','Unknown'),
                (playing or {}).get('description',''))
            xbmcgui.Dialog().textviewer(channel.get('label','Live TV'), msg)
            continue
        if action == 'sources':
            labels = [s.get('name') or 'Source {}'.format(i+1) for i,s in enumerate(sources)]
            selected = xbmcgui.Dialog().select('Preferred stream — '+channel.get('label',''), labels)
            if selected >= 0:
                save_preference(channel_key(channel), sources[selected]['id'])
            continue
        if action == 'play':
            if not sources:
                continue
            ids = [int(s['id']) for s in sources]
            preferred = preferences().get(channel_key(channel))
            source_id = preferred if preferred in ids else ids[0]
            try:
                data = endpoint('/api/live/channel/'+str(source_id))
                url = data.get('url','')
                if not url.startswith(('http://','https://')):
                    raise ValueError('Stream URL unavailable')
                item = xbmcgui.ListItem(path=url)
                item.setInfo('video', {'title': channel.get('label','Live TV'), 'mediatype':'video'})
                # Modal has already closed. Give Kodi a clean video-window transition
                # for every selection, not only the first playback session.
                xbmc.executebuiltin('Dialog.Close(all,true)')
                player = xbmc.Player()
                player.play(url, item)
                monitor = xbmc.Monitor()
                # Wait for playback to begin, then for it to end. Guide stays closed during playback.
                for _ in range(80):
                    if monitor.abortRequested(): return
                    if player.isPlaying():
                        # Kodi can leave the previous EPG window active when playback
                        # starts from a script-driven list after a prior stop.
                        xbmc.executebuiltin('ActivateWindow(fullscreenvideo)')
                        break
                    monitor.waitForAbort(0.25)
                else:
                    xbmcgui.Dialog().notification('KodiFlix Live','Playback did not start',xbmcgui.NOTIFICATION_WARNING,3000)
                    continue
                # Wait until actual stop before returning to guide; ignore brief transitions.
                stopped_at = None
                while not monitor.abortRequested():
                    if player.isPlaying():
                        stopped_at = None
                    else:
                        if stopped_at is None:
                            stopped_at = time.monotonic()
                        elif time.monotonic() - stopped_at >= 1.5:
                            break
                    monitor.waitForAbort(0.25)
            except Exception as exc:
                xbmc.log('KodiFlix Live playback: '+repr(exc), xbmc.LOGERROR)
                xbmcgui.Dialog().notification('KodiFlix Live',str(exc)[:100],xbmcgui.NOTIFICATION_ERROR,4000)
