# -*- coding: utf-8 -*-
import ftplib
import json
import os
import socket
import uuid
from datetime import datetime
from urllib.request import urlopen

import xbmc
import xbmcvfs

from resources.lib.utils.log_utils import get_logger

log = get_logger()

UPLOAD_INTERVAL_SEC = 12 * 3600
IPIFY_TIMEOUT_SEC = 2
FTP_TIMEOUT_SEC = 15

INSTALL_ID_FILE = "telemetry_install_id.txt"
START_LOG_FILE = "telemetry_start_log.jsonl"
PENDING_LOG_FILE = "telemetry_pending.jsonl"
LAST_UPLOAD_FILE = "telemetry_last_upload.txt"
MONTH_SNAPSHOT_FILE = "telemetry_month_snapshot.jsonl"


def _profile_dir(addon):
    return xbmcvfs.translatePath(addon.getAddonInfo("profile"))


def _ensure_profile_dir(path):
    try:
        if not xbmcvfs.exists(path):
            xbmcvfs.mkdirs(path)
    except Exception:
        pass


def _path(addon, filename):
    pdir = _profile_dir(addon)
    _ensure_profile_dir(pdir)
    return os.path.join(pdir, filename)


def _read_text(path, default=""):
    try:
        with open(path, "r", encoding="utf-8") as f:
            return f.read().strip()
    except Exception:
        return default


def _write_text(path, value):
    with open(path, "w", encoding="utf-8") as f:
        f.write(value or "")


def _append_jsonl(path, row):
    with open(path, "a", encoding="utf-8") as f:
        f.write(json.dumps(row, ensure_ascii=False) + "\n")


def _get_or_create_install_id(addon):
    path = _path(addon, INSTALL_ID_FILE)
    val = _read_text(path, "")
    if val:
        return val
    val = str(uuid.uuid4())
    _write_text(path, val)
    return val


def _get_public_ip():
    try:
        with urlopen("https://api.ipify.org?format=json", timeout=IPIFY_TIMEOUT_SEC) as resp:
            data = json.loads((resp.read() or b"{}").decode("utf-8", "ignore"))
            ip = (data.get("ip") or "").strip()
            return ip or None
    except Exception:
        return None


def _get_local_ip():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(("8.8.8.8", 80))
        ip = s.getsockname()[0]
        s.close()
        return ip
    except Exception:
        return None


def _get_device_name():
    try:
        friendly = (xbmc.getInfoLabel("System.FriendlyName") or "").strip()
        if friendly:
            return friendly
    except Exception:
        pass
    try:
        return socket.gethostname() or None
    except Exception:
        return None


def _build_start_row(addon):
    return {
        "event": "start",
        "ts": datetime.now().astimezone().isoformat(timespec="seconds"),
        "install_id": _get_or_create_install_id(addon),
        "addon_ver": addon.getAddonInfo("version"),
        "kodi_ver": (xbmc.getInfoLabel("System.BuildVersion") or "").strip(),
        "platform": (xbmc.getInfoLabel("System.OSVersionInfo") or "").strip(),
        "device_name": _get_device_name(),
        "public_ip": _get_public_ip(),
        "local_ip": _get_local_ip(),
    }


def _needs_upload(addon):
    last_path = _path(addon, LAST_UPLOAD_FILE)
    last_raw = _read_text(last_path, "0")
    try:
        last_ts = float(last_raw)
    except Exception:
        last_ts = 0.0
    return (datetime.now().timestamp() - last_ts) >= UPLOAD_INTERVAL_SEC


def _set_uploaded_now(addon):
    _write_text(_path(addon, LAST_UPLOAD_FILE), str(datetime.now().timestamp()))


def _build_month_snapshot(addon):
    src = _path(addon, START_LOG_FILE)
    out = _path(addon, MONTH_SNAPSHOT_FILE)
    month_prefix = datetime.now().strftime("%Y-%m")
    try:
        with open(src, "r", encoding="utf-8") as fin, open(out, "w", encoding="utf-8") as fout:
            for line in fin:
                line = (line or "").strip()
                if not line:
                    continue
                try:
                    row = json.loads(line)
                except Exception:
                    continue
                ts = str(row.get("ts") or "")
                if ts.startswith(month_prefix):
                    fout.write(json.dumps(row, ensure_ascii=False) + "\n")
        return out
    except Exception:
        return None


def _ensure_remote_tree(ftp, path):
    parts = [p for p in (path or "").split("/") if p]
    if not parts:
        return
    cur = ""
    for part in parts:
        cur += "/" + part
        try:
            ftp.mkd(cur)
        except Exception:
            pass


def _upload_month_snapshot(addon):
    from resources.lib.utils.cloud_sync import CloudSync

    install_id = _get_or_create_install_id(addon)
    snap = _build_month_snapshot(addon)
    if not snap or not os.path.exists(snap):
        return False

    month_name = datetime.now().strftime("%Y-%m")
    remote_dir = "{}/_telemetry/{}".format(CloudSync.FTP_ROOT.rstrip("/"), install_id)
    remote_file = "{}/start-{}.jsonl".format(remote_dir, month_name)
    tmp_file = remote_file + ".part"

    ftp = None
    try:
        ftp = ftplib.FTP()
        ftp.connect(CloudSync.FTP_HOST, CloudSync.FTP_PORT, timeout=FTP_TIMEOUT_SEC)
        ftp.login(CloudSync.FTP_USER, CloudSync.FTP_PASS)
        try:
            ftp.voidcmd("TYPE I")
        except Exception:
            pass
        try:
            ftp.set_pasv(True)
        except Exception:
            pass

        _ensure_remote_tree(ftp, remote_dir)

        with open(snap, "rb") as f:
            ftp.storbinary("STOR " + tmp_file, f)
        try:
            ftp.rename(tmp_file, remote_file)
        except Exception:
            ftp.sendcmd("RNFR " + tmp_file)
            ftp.sendcmd("RNTO " + remote_file)

        # === GLOBÁLNÍ LOG ===
        try:
            global_dir = "{}/_telemetry".format(CloudSync.FTP_ROOT.rstrip("/"))
            global_file = "{}/all_users-{}.jsonl".format(global_dir, month_name)
            pending_path = _path(addon, PENDING_LOG_FILE)
            if os.path.exists(pending_path) and os.path.getsize(pending_path) > 0:
                _ensure_remote_tree(ftp, global_dir)
                with open(pending_path, "rb") as f:
                    ftp.storbinary("APPE " + global_file, f)
                try:
                    os.remove(pending_path)
                except Exception:
                    _write_text(pending_path, "")
                log.debug("Telemetry global log appended successfully.")
        except Exception as gex:
            log.debug("Telemetry global log append failed: %s", gex)

        return True
    except Exception as ex:
        log.debug("Telemetry upload skipped/failed: %s", ex)
        try:
            if ftp:
                ftp.delete(tmp_file)
        except Exception:
            pass
        return False
    finally:
        try:
            if ftp:
                ftp.quit()
        except Exception:
            try:
                if ftp:
                    ftp.close()
            except Exception:
                pass


def log_start_event(addon):
    try:
        row = _build_start_row(addon)
        _append_jsonl(_path(addon, START_LOG_FILE), row)
        _append_jsonl(_path(addon, PENDING_LOG_FILE), row)
    except Exception as ex:
        log.debug("Telemetry start log skipped: %s", ex)


def maybe_upload(addon):
    try:
        if not _needs_upload(addon):
            return
        if _upload_month_snapshot(addon):
            _set_uploaded_now(addon)
    except Exception as ex:
        log.debug("Telemetry maybe_upload skipped: %s", ex)


def read_local_start_log(addon):
    try:
        p = _path(addon, START_LOG_FILE)
        if not os.path.exists(p):
            return "Telemetry log je zatím prázdný (soubor neexistuje)."
        with open(p, "r", encoding="utf-8") as f:
            txt = f.read().strip()
        return txt or "Telemetry log je prázdný."
    except Exception as ex:
        return "Chyba čtení telemetry logu: {}".format(ex)


def read_month_snapshot(addon):
    try:
        p = _path(addon, MONTH_SNAPSHOT_FILE)
        if not os.path.exists(p):
            return "Měsíční snapshot zatím neexistuje."
        with open(p, "r", encoding="utf-8") as f:
            txt = f.read().strip()
        return txt or "Měsíční snapshot je prázdný."
    except Exception as ex:
        return "Chyba čtení snapshotu: {}".format(ex)


def upload_now(addon):
    try:
        ok = _upload_month_snapshot(addon)
        if ok:
            _set_uploaded_now(addon)
        return ok
    except Exception:
        return False
