# -*- coding: utf-8 -*-
"""QR Code login for cloud storage providers.

Supports: 115 Open, Aliyundrive Open, 189 Cloud.

Uses session-based polling: Start → Show QR → Poll for status → Close.
"""

import os
import tempfile
import urllib.request

import xbmc
import xbmcgui

from .cd2_client import get_client
from .cd2_constants import QR_LOGIN_PROVIDERS
from .cd2_dialogs import notification
from .cd2_l10n import _, __
from . import cd2_utils

log = cd2_utils.log

# Proxy bypass opener (same pattern as cd2_client)
_proxy_handler = urllib.request.ProxyHandler({})
_url_opener = urllib.request.build_opener(_proxy_handler)


def qr_login_select():
    """Show a list of available QR-login providers, return selected key or None."""
    providers = list(QR_LOGIN_PROVIDERS.values())
    names = [f"{p['name']} - {p['desc']}" for p in providers]
    from xbmcgui import Dialog
    idx = Dialog().select(_(32099), names)
    if idx < 0:
        return None
    return list(QR_LOGIN_PROVIDERS.keys())[idx]


def qr_login_do(provider_key):
    """
    Execute QR code login for the given provider.
    Opens a progress dialog, shows QR code, polls for status.
    Returns True on success.
    """
    provider = QR_LOGIN_PROVIDERS.get(provider_key)
    if not provider:
        return False

    client = get_client()

    # Pre-check: can user add more cloud drives?
    try:
        can_add = client.can_add_more_cloud_apis(timeout=5)
        if not can_add.success:
            xbmcgui.Dialog().ok(_(32030), can_add.errorMessage or _(32056))
            return False
    except Exception as e:
        xbmcgui.Dialog().ok(_(32030), str(e))
        return False

    # Start the QR login stream - get first message immediately
    try:
        first_msg = client.qr_login_start(provider_key, timeout=120)
    except Exception as e:
        log(f"QR login start error: {e}", xbmc.LOGERROR)
        xbmcgui.Dialog().ok(_(32090), str(e))
        return False

    session_id = getattr(first_msg, 'session', None)
    if not session_id:
        xbmcgui.Dialog().ok(_(32090), _(32091))
        return False

    msg_type = first_msg.messageType
    text = first_msg.message

    # Download QR image
    tmpdir = tempfile.gettempdir()
    img_path = os.path.join(tmpdir, f"cd2_qr_{provider_key}.png")
    qr_ready = False

    if msg_type == 0:  # SHOW_IMAGE - URL points to QR image
        qr_ready = _download_direct_image(text, img_path)
    elif msg_type == 1:  # SHOW_IMAGE_CONTENT - text to encode as QR
        qr_ready = _download_qr_image(text, img_path)

    if not qr_ready:
        log(f"Failed to get QR image for {provider_key}")
        xbmcgui.Dialog().ok(_(32090), _(32092))
        return False

    # Create a window that shows QR code AND status updates together
    window, status_label = _create_qr_window(img_path, provider["name"], _(32094))
    window.setProperty("_cd2_qr_active", "1")
    window.show()

    try:
        poll_count = 0
        max_polls = 360  # ~3 minutes (360 * 0.5s)
        while poll_count < max_polls:
            poll_count += 1
            xbmc.sleep(500)

            # Detect user pressing Back
            if window.cancelled:
                log("QR window closed by user, cancelling session")
                client.qr_login_cancel(session_id)
                return False

            try:
                poll = client.qr_login_poll(session_id, timeout=5)
            except Exception as e:
                log(f"QR poll error: {e}", xbmc.LOGWARNING)
                continue

            closed = getattr(poll, 'closed', False)
            msg_type = getattr(poll, 'messageType', None)
            text = getattr(poll, 'message', "") or ""
            log(f"QR poll #{poll_count}: closed={closed} msgType={msg_type} msg={text[:60]}")

            if closed:
                status_label.setLabel(f"[B]{_(32095)}[/B]")
                xbmc.sleep(500)
                window.close()
                err = getattr(poll, 'error', None)
                if err:
                    xbmcgui.Dialog().ok(_(32090), str(err))
                    return False
                else:
                    notification("CloudDrive2", _(32012))
                    return True

            if msg_type is None:
                continue

            if msg_type == 2:  # CHANGE_STATUS
                status_label.setLabel(f"[B]{text or _(32096)}[/B]")

            elif msg_type == 3:  # CLOSE
                log("QR login CLOSE received!")
                status_label.setLabel(f"[B]{_(32097)}[/B]")
                xbmc.sleep(300)
                window.close()
                return True

            elif msg_type == 4:  # ERROR
                log(f"QR login ERROR: {text}")
                status_label.setLabel(f"[B]{_(32090)}: {text}[/B]" if text else f"[B]{_(32090)}[/B]")
                xbmc.sleep(1500)
                window.close()
                client.qr_login_cancel(session_id)
                return False

        # Timed out
        status_label.setLabel(f"[B]{_(32098)}[/B]")
        xbmc.sleep(1500)
        window.close()
        client.qr_login_cancel(session_id)
        return False

    except Exception as e:
        window.close()
        client.qr_login_cancel(session_id)
        log(f"QR login error: {e}", xbmc.LOGERROR)
        xbmcgui.Dialog().ok(_(32090), str(e))
        return False


QR_API_BASE = "https://api.2dcode.biz/v1/create-qr-code"


def _download_direct_image(url, local_path):
    """Download an image directly from URL (SHOW_IMAGE)."""
    try:
        resp = _url_opener.open(url, timeout=30)
        with open(local_path, "wb") as f:
            f.write(resp.read())
        return True
    except Exception as e:
        log(f"Failed to download direct image: {e}", xbmc.LOGWARNING)
        return False


def _download_qr_image(content, local_path):
    """Generate QR code via online API and download to local path."""
    qr_api_url = QR_API_BASE + "?data=" + urllib.parse.quote(content)
    try:
        resp = _url_opener.open(qr_api_url, timeout=30)
        with open(local_path, "wb") as f:
            f.write(resp.read())
        return True
    except Exception as e:
        log(f"Failed to download QR image: {e}", xbmc.LOGWARNING)
        return False


class _QRWindow(xbmcgui.Window):
    """QR code window that detects Back press via onAction."""

    def __init__(self):
        super().__init__(-1)
        self.cancelled = False

    def onAction(self, action):
        aid = action.getId()
        if aid in (10, 92):  # ACTION_PREVIOUS_MENU (10) or ACTION_NAV_BACK (92)
            self.cancelled = True
            # Don't close here - let polling loop show status then close


def _create_qr_window(image_path, title, status_text):
    """Create a _QRWindow with QR code image and an updatable status label.
    Returns (window, status_label) tuple.
    """
    window = _QRWindow()

    # Background
    window.addControl(xbmcgui.ControlImage(0, 0, 1280, 720, ""))

    # Title
    window.addControl(xbmcgui.ControlLabel(40, 20, 1200, 50,
                      f"[B]{_(32093, title)}[/B]",
                      font="font13", textColor="0xFFFFFFFF"))

    # QR code image centered
    img_size = 400
    img_x = (1280 - img_size) // 2
    img_y = 120
    window.addControl(xbmcgui.ControlImage(img_x, img_y, img_size, img_size, image_path))

    # Status text below QR — keep reference for updates
    status_label = xbmcgui.ControlLabel(40, img_y + img_size + 30, 1200, 60,
                                        f"[B]{status_text}[/B]",
                                        font="font13", textColor="0xFFFFFF00",
                                        alignment=2)
    window.addControl(status_label)

    return window, status_label
