# -*- coding: utf-8 -*-
import configparser
import logging
import os
import pathlib
from threading import Thread, Timer
from datetime import datetime
import yaml

from pymrf4.bt_client import BTClient
from pymrf4.entities import ApiConfig, SiteConfig
from pymrf4.mrf_proxy import start_server, shutdown_server
from pymrf4.utils import format_info_hash, set_interval
from pymrf4.web_ui import start_web_ui
from pymrf4.models import create_tables, Torrent, Announce
from pymrf4.harvestor import Harvestor
from pymrf4.db import db


logger = logging.getLogger(__name__)


class MRFContext:
    def __init__(self):
        self.timers: list[Timer] = []
        self.prepare()

    def prepare(self):
        # self.read_config()
        self.read_config()

        self.bt_client = None
        try:
            self.init_bt_client()
        except:
            logger.info("Failed to init BT client, continue without it.")

        if self.bt_client:
            self.start_timers()

        # prepare database, create db file if not exists
        create_tables()

        Harvestor.setup(self.harvestor_config)


    def start_timers(self):
        self.timers.append(set_interval(self.sync_torrents, 5))

    def stop_timers(self):
        for t in self.timers:
            t.cancel()


    def read_config(self):
        config = yaml.load(open(os.path.join(os.getcwd(), "config.yml"), "r"), Loader=yaml.Loader)

        defaults = config.get("defaults", {})

        self.sites = {}
        for site in config.get("sites", []):
            site_name = site["name"]
            merged_site = {**defaults, **site}
            self.sites[site_name] = SiteConfig(**merged_site)
            logger.info(f"> Site: {site_name} {repr(self.sites[site_name])}")

        self.api_config = ApiConfig(**config.get("api", {}))
        self.harvestor_config = config.get("harvestor", {})


    def init_bt_client(self):
        self.bt_client = BTClient(self.api_config)
        if self.bt_client:
            self.bt_client.login()

    @db.connection_context()
    def sync_torrents(self):
        if not self.bt_client:
            return 
        started = datetime.now()
        all_from_client = self.bt_client.get_torrents()
        all_torrents_in_db = Torrent.select()

        counter = 0
        update_payload = []
        to_be_deleted = []

        for t in all_torrents_in_db:
            info_hash = t.info_hash
            if info_hash in all_from_client:
                t_from_client = all_from_client[info_hash]

                if t.name is None or t.name != t_from_client["name"]:
                    t.name = t_from_client["name"]
                    t.size = t_from_client["size"]

                    # previously paused, but not synced
                    if "paused" in t_from_client["state"]:
                        t.last_event = "stopped"

                    update_payload.append(t)

                    logger.debug(f"Synced {t.name}")
            else:
                # not even in client, delete it
                to_be_deleted.append(t.id)

        if len(update_payload) > 0:
            counter = Torrent.bulk_update(update_payload, fields=["name", "size"], batch_size=100)
            logger.debug(f"Synced {counter} torrents.")

        for t_id in to_be_deleted:
            with db.atomic():
                logger.info(f"Deleting {t_id}...")
                Torrent.get_by_id(t_id).delete_instance(recursive=True)
                logger.info(f"Deleted {t_id}.")

    def spin_up_daemons(self, host="0.0.0.0", port=9050, web_ui_port=5090):
        self.socks5 = Thread(target=start_server, kwargs={"host": host, "port": port, "config": self.sites})
        self.socks5.name = "Socks5 Proxy"
        self.socks5.start()

        self.web_ui = Thread(target=start_web_ui, kwargs={"host": host, "port": web_ui_port, "mrf_ctx": self})
        self.web_ui.name = "WebUI"
        self.web_ui.daemon = True
        self.web_ui.start()


    def shutdown_daemons(self):
        if self.socks5:
            logger.info("shutdown socks5 proxy...")
            # self.socks5.terminate()
            # self.socks5.join()
            shutdown_server()

        if self.web_ui:
            logger.info("shutdown webui server...")
            self.web_ui.join()



# {'added_on': 1725814149,
# 'amount_left': 0,
# 'auto_tmm': True,
# 'availability': 1,
# 'category': 'M-Team Movies',
# 'completed': 7183989307,
# 'completion_on': 1725814530,
# 'content_path': 'D:\\BT\\incoming\\M-Team-Movies\\Eye.for.an.Eye.The.Blind.Swordsman.2022.BluRay.1080p.x26....BluRay.1080p.x264.DTS-HD.MA.5.1-MTeam.mkv',
# 'dl_limit': 0,
# 'dlspeed': 0,
# 'download_path': 'D:\\BT\\temp',
# 'downloaded': 7234399427,
# 'downloaded_session': 0,
# 'eta': 8640000,
# 'f_l_piece_prio': False,
# 'force_start': False,
# 'inactive_seeding_time_limit': -2,
# 'infohash_v1': '90b8263c117d76b385a2cee752181e385da97653',
# 'infohash_v2': '',
# 'last_activity': 1726033229,
# 'magnet_uri': ''magnet:?xt=urn:btih:90b8263c117d76b385a2cee752181e385da97653&dn=Eye.for.an.Eye.The.Blind.Swordsman.2022.BluRay.1080p.x264.DTS-HD.MA.5.1-MTeam&tr=https%3A%2F%2Ftracker.m-team.cc%2Fannounce%3Fcredential%3Dc2lnbj04OWRjMzUwNzFjYzVmYTc5ZjA0YzRmYmMxOTIxNWQ3MyZ0PTE3MjU4MTQxNDgmdGlkPTgyMzM3OCZ1aWQ9MTc1NjQz'',
# 'max_inactive_seeding_time': -1,
# 'max_ratio': 1,
# 'max_seeding_time': -1,
# 'name': 'Eye.for.an.Eye.The.Blind.Swordsman.2022.BluRay.1080p.x264.DTS-HD.MA.5.1-MTeam',
# 'num_complete': 168,
# 'num_incomplete': 0,
# 'num_leechs': 0,
# 'num_seeds': 0,
# 'priority': 0,
# 'progress': 1,
# 'ratio': 0.13661361996566462,
# 'ratio_limit': -2,
# 'save_path': 'D:\\BT\\incoming\\M-Team-Movies',
# 'seeding_time': 217602,
# 'seeding_time_limit': -2,
# 'seen_complete': 1725972441,
# 'seq_dl': False,
# 'size': 7183989307,
# 'state': 'queuedUP',
# 'super_seeding': False,
# 'tags': '',
# 'time_active': 217982,
# 'total_size': 7183989307,
# 'tracker': 'https://tracker.m-team.cc/announce?credential=c2lnbj04OWRjMzUwNzFjYzVmYTc5ZjA0YzRmYmM...E3MjU4MTQxNDgmdGlkPTgyMzM3OCZ1aWQ9MTc1NjQz',
# 'trackers_count': 1,
# 'up_limit': 0,
# 'uploaded': 988317494,
# 'uploaded_session': 0,
# 'upspeed': 0}
