import os
from threading import Thread
from time import time

import xbmc
import xbmcaddon
import xbmcvfs

from lib.api.trakt.base_cache import setup_databases
from lib.services.migrations import run_migrations
from lib.services.preloader import StartupPreloader
from lib.services.trakt_sync import TraktSyncService
from lib.updater import updates_check_addon
from lib.utils.kodi.settings import update_delay
from lib.utils.kodi.utils import (
    clear_cached_settings,
    clear_property,
    dialog_ok,
    get_kodi_version,
    get_property_no_fallback,
    get_setting,
    kodilog,
    set_property_no_fallback,
    translatePath,
    translation,
)

first_run_update_prop = "jacktook.first_run_update"
pause_services_prop = "jacktook.pause_services"


class CheckKodiVersion:
    def run(self):
        kodilog("Checking Kodi version...")
        if get_kodi_version() < 20:
            dialog_ok(
                heading=xbmcaddon.Addon().getAddonInfo("name"),
                line1=translation(90559),
            )


class DatabaseSetup:
    def run(self):
        setup_databases()


class UpdateCheck:
    def run(self):
        kodilog("Update Check Service Started...", level=xbmc.LOGINFO)
        if get_property_no_fallback(first_run_update_prop) == "true":
            kodilog("Update check already performed, skipping...", level=xbmc.LOGINFO)
            return

        try:
            end_pause = time() + update_delay()
            monitor = xbmc.Monitor()
            player = xbmc.Player()

            while not monitor.abortRequested():
                while time() < end_pause:
                    monitor.waitForAbort(1)
                while player.isPlayingVideo():
                    monitor.waitForAbort(1)
                set_property_no_fallback(first_run_update_prop, "true")
                updates_check_addon(automatic=True)
                break

            kodilog("Update Check Service Finished", level=xbmc.LOGINFO)
        except Exception as e:
            kodilog(e, level=xbmc.LOGERROR)


def TMDBHelperAutoInstall():
    jacktook_select_path = "special://home/addons/plugin.video.jacktook/jacktook.select.json"

    if not xbmcvfs.exists(jacktook_select_path):
        kodilog("jacktook.select.json file not found!", level=xbmc.LOGERROR)
        return

    target_addons = [
        "plugin.video.themoviedb.helper",
        "plugin.video.tmdb.bingie.helper",
    ]

    source_content = _read_text_file(jacktook_select_path)
    if source_content is None:
        kodilog("Unable to read bundled jacktook.select.json", level=xbmc.LOGERROR)
        return

    for addon_id in target_addons:
        try:
            _ = xbmcaddon.Addon(addon_id)
        except RuntimeError:
            kodilog(
                f"{addon_id} addon not found, skipping auto-install.",
                level=xbmc.LOGINFO,
            )
            continue

        tmdb_helper_path = (
            f"special://home/addons/{addon_id}/resources/players/jacktook.select.json"
        )

        target_content = _read_text_file(tmdb_helper_path)
        if target_content == source_content:
            continue

        target_dir = os.path.dirname(translatePath(tmdb_helper_path))
        if target_dir and not xbmcvfs.exists(target_dir):
            xbmcvfs.mkdirs(target_dir)

        if xbmcvfs.exists(tmdb_helper_path):
            xbmcvfs.delete(tmdb_helper_path)

        ok = xbmcvfs.copy(jacktook_select_path, tmdb_helper_path)
        if ok:
            kodilog(
                f"Installed or updated jacktook.select.json file for {addon_id}!",
                level=xbmc.LOGINFO,
            )
        else:
            kodilog(
                f"Error installing jacktook.select.json file for {addon_id}!",
                level=xbmc.LOGERROR,
            )


def _read_text_file(path):
    translated_path = translatePath(path)
    if not translated_path or not os.path.exists(translated_path):
        return None

    try:
        with open(translated_path, encoding="utf-8") as file_obj:
            return file_obj.read()
    except OSError as error:
        kodilog(f"Failed to read {path}: {error}", level=xbmc.LOGERROR)
        return None


class DownloaderSetup:
    def run(self):
        download_dir = get_setting("download_dir")
        translated_path = translatePath(download_dir)
        if not xbmcvfs.exists(translated_path):
            xbmcvfs.mkdir(translated_path)


class DebridExpirationCheck:
    def run(self):
        kodilog("Debrid Expiration Check Service Started...", level=xbmc.LOGINFO)
        if not get_setting("debrid_expiration_enabled"):
            return

        try:
            threshold = int(get_setting("debrid_expiration_threshold", 3))

            def notify_expiration(name, days):
                from lib.utils.kodi.utils import notification, translation

                if days == 0:
                    msg = translation(90231) % name
                else:
                    msg = translation(90230) % (name, days)
                notification(msg, time=5000)

            if get_setting("real_debrid_enabled") and get_setting("real_debrid_token"):
                from lib.api.debrid.realdebrid import RealDebrid

                rd = RealDebrid(str(get_setting("real_debrid_token", "")))
                days = rd.days_remaining()
                if days is not None and days <= threshold:
                    notify_expiration("Real-Debrid", days)

            alldebrid_token = get_setting("alldebrid_token")
            if get_setting("alldebrid_enabled") and alldebrid_token:
                from lib.api.debrid.alldebrid import AllDebrid

                ad = AllDebrid(str(alldebrid_token))
                days = ad.days_remaining()
                if days is not None and days <= threshold:
                    notify_expiration("AllDebrid", days)

            if get_setting("torbox_enabled") and get_setting("torbox_token"):
                from lib.api.debrid.torbox import Torbox

                tb = Torbox(get_setting("torbox_token"))
                days = tb.days_remaining()
                if days is not None and days <= threshold:
                    notify_expiration("Torbox", days)

            if get_setting("premiumize_enabled") and get_setting("premiumize_token"):
                from lib.api.debrid.premiumize import Premiumize

                pm = Premiumize(str(get_setting("premiumize_token", "")))
                days = pm.days_remaining()
                if days is not None and days <= threshold:
                    notify_expiration("Premiumize", days)

            if get_setting("debrider_enabled") and get_setting("debrider_token"):
                from lib.api.debrid.debrider import Debrider

                db = Debrider(get_setting("debrider_token"))
                days = db.days_remaining()
                if days is not None and days <= threshold:
                    notify_expiration("Debrider", days)

        except Exception as e:
            kodilog(f"Error in DebridExpirationCheck: {e}", level=xbmc.LOGERROR)


class JacktookMOnitor(xbmc.Monitor):
    def __init__(self):
        xbmc.Monitor.__init__(self)
        self.startServices()

    def startServices(self):
        CheckKodiVersion().run()
        DatabaseSetup().run()
        run_migrations()
        Thread(target=UpdateCheck().run).start()
        Thread(target=TraktSyncService().run).start()
        Thread(target=DebridExpirationCheck().run).start()
        StartupPreloader().run()
        DownloaderSetup().run()
        TMDBHelperAutoInstall()
        try:
            from lib.services.autostart import AutoStartService

            AutoStartService().run()
        except Exception as e:
            kodilog(f"AutoStart failed: {e}", level=xbmc.LOGERROR)
        try:
            from lib.services.widget_refresh import WidgetRefreshService

            Thread(target=WidgetRefreshService().run).start()
        except Exception as e:
            kodilog(f"WidgetRefresh failed: {e}", level=xbmc.LOGERROR)

    def onScreensaverActivated(self):
        set_property_no_fallback(pause_services_prop, "true")
        kodilog("PAUSING Jacktook Services Due to Device Sleep", level=xbmc.LOGINFO)

    def onScreensaverDeactivated(self):
        clear_property(pause_services_prop)
        kodilog("UNPAUSING Jacktook Services Due to Device Awake", level=xbmc.LOGINFO)

    def onSettingsChanged(self):
        clear_cached_settings()
        from lib.utils.tmdb_init import ensure_tmdb_init

        ensure_tmdb_init()
        kodilog(
            "Cleared cached settings and refreshed TMDB language after Kodi settings change",
            level=xbmc.LOGINFO,
        )

    def onNotification(self, sender, method, data):
        if method == "System.OnSleep":
            set_property_no_fallback(pause_services_prop, "true")
            kodilog(
                "PAUSING Jacktook Services Due to Device Sleep",
                level=xbmc.LOGINFO,
            )
        elif method == "System.OnWake":
            clear_property(pause_services_prop)
            kodilog(
                "UNPAUSING Jacktook Services Due to Device Awake",
                level=xbmc.LOGINFO,
            )
