"""
S3 — Pair new device (scanning).

Spec: device rows 64px @ y 60/132/204/276; scanning chip in status bar
center; progress bar @ y386 with "N devices · Ns remaining"; A pair,
B cancel. Design preview uses mock rows only when AAHEAD_LIVE_BACKEND is off.
"""

from __future__ import annotations

import pygame

from ..design import tokens as t
from ..shared import widgets as w
from ..shared import fonts
from ..shared import backend

ROW_X, ROW_W, ROW_H = 16, 608, 64
ROW_Y = (60, 132, 204, 276)
SCAN_SECONDS = 20


class PairScreen:
    name = "pair"

    def __init__(self, app):
        self.app = app
        self.devices = []
        self.focus = 0
        self.elapsed = 0.0       # ms scanning
        self.scan_job = None
        self.pair_job = None
        self.poll_ms = 0.0
        self.scan_done = False
        self.scan_progress = 0.0
        self.job_progress = 0.0
        self.status = "Scanning nearby…"
        self._start_scan()

    def _fallback_devices(self):
        self.devices = [
            {"mac": "", "name": "AirPods Pro", "sub": "Apple · Audio", "icon": "ph-headphones", "rssi": 4},
            {"mac": "", "name": "BT-MUSIC", "sub": "Speaker", "icon": "ph-speaker-high", "rssi": 3},
            {"mac": "", "name": "Pixel Buds Pro", "sub": "Google · Audio", "icon": "ph-headphones", "rssi": 2},
            {"mac": "", "name": "Sony WH-1000XM4", "sub": "Headphones", "icon": "ph-headphones", "rssi": 1},
        ]

    def _start_scan(self):
        self.devices = []
        self.focus = 0
        self.elapsed = 0.0
        self.scan_done = False
        self.scan_progress = 0.0
        self.status = "Scanning nearby…"
        env = backend.bluetooth_scan_async(SCAN_SECONDS)
        if not env:
            if backend.live_enabled():
                self.status = "Scan unavailable"
                backend.gui_log("pair.scan_unavailable")
                self.app.toast(self.status)
            else:
                self._fallback_devices()
                self.status = "Preview devices"
            self.scan_done = True
            return
        job = ((env.get("data") or {}).get("job") or {})
        if job.get("job_id"):
            self.scan_job = job["job_id"]
            backend.gui_log("pair.scan_started", job_id=self.scan_job)
            return
        if not env.get("ok"):
            self.status = env.get("title") or "Scan unavailable"
            backend.gui_log("pair.scan_failed_start", title=env.get("title"), state=env.get("state"))
            self.app.toast(self.status)
            self.scan_done = True

    def on_action(self, action):
        if action == "up":
            if self.devices:
                self.focus = max(0, self.focus - 1)
        elif action == "down":
            if self.devices:
                self.focus = min(len(self.devices) - 1, self.focus + 1)
        elif action == "b":
            self.app.pop()
        elif action == "a":
            if self.scan_done and not self.devices and not self.scan_job:
                self._start_scan()
                return
            if not self.devices or self.pair_job:
                return
            dev = self.devices[self.focus]
            name = dev["name"]
            mac = dev.get("mac") or ""
            if not mac:
                self.app.toast(f"Pairing {name}…")
                return
            env = backend.bluetooth_pair(mac)
            job = (((env or {}).get("data") or {}).get("job") or {})
            if job.get("job_id"):
                self.pair_job = job["job_id"]
                self.job_progress = 0.05
                self.status = f"Pairing {name}…"
                backend.gui_log("pair.job_started", job_id=self.pair_job, mac=mac, name=name)
                self.app.toast(self.status)
            else:
                self.app.toast((env or {}).get("title") or "Pairing unavailable")

    def update(self, dt_ms):
        self.elapsed += dt_ms
        self.poll_ms += dt_ms
        if self.poll_ms < 450:
            return
        self.poll_ms = 0.0
        if self.pair_job:
            env = backend.job_status(self.pair_job)
            if not env:
                return
            job = ((env.get("data") or {}).get("job") or {})
            progress = job.get("progress") or {}
            self.status = progress.get("phase") or job.get("title") or self.status
            pct = progress.get("percent")
            if isinstance(pct, int | float):
                self.job_progress = max(self.job_progress, max(0.0, min(1.0, float(pct) / 100.0)))
            state = job.get("state")
            if state == "completed":
                self.job_progress = 1.0
                backend.gui_log("pair.job_completed", job_id=self.pair_job, title=job.get("title"))
                self.pair_job = None
                self.app.toast(job.get("summary") or "Bluetooth device paired")
                self.app.pop()
            elif state == "failed":
                self.job_progress = 1.0
                backend.gui_log("pair.job_failed", job_id=self.pair_job, title=job.get("title"))
                self.pair_job = None
                self.app.toast(job.get("title") or "Pairing failed")
            return
        if self.scan_job:
            env = backend.job_status(self.scan_job)
            if not env:
                return
            job = ((env.get("data") or {}).get("job") or {})
            progress = job.get("progress") or {}
            self.status = progress.get("phase") or self.status
            pct = progress.get("percent")
            if isinstance(pct, int | float):
                self.scan_progress = max(self.scan_progress, max(0.0, min(0.96, float(pct) / 100.0)))
            state = job.get("state")
            if state == "completed":
                result = job.get("result") or {}
                live = []
                for dev in result.get("devices") or []:
                    name = dev.get("name") or dev.get("mac") or "Bluetooth device"
                    kind = dev.get("kind")
                    live.append({
                        "mac": dev.get("mac") or "",
                        "name": name,
                        "sub": "Audio device" if kind == "audio" else "Bluetooth device",
                        "icon": "ph-headphones" if kind == "audio" else "ph-bluetooth",
                        "rssi": 3,
                    })
                self.devices = live[:4]
                self.focus = min(self.focus, max(0, len(self.devices) - 1))
                self.scan_done = True
                self.scan_progress = 1.0
                self.scan_job = None
                self.status = f"{len(self.devices)} devices found" if self.devices else "Nothing nearby"
                backend.gui_log("pair.scan_completed", count=len(self.devices))
            elif state == "failed":
                self.scan_done = True
                self.scan_progress = 1.0
                self.scan_job = None
                self.status = job.get("title") or "Scan failed"
                backend.gui_log("pair.scan_failed", title=job.get("title"))
                result = job.get("result") or {}
                if result.get("reason") == "no_adapter":
                    from .bt_states import S2bNoAdapter
                    self.app.pop()
                    self.app.push(S2bNoAdapter(self.app))
                    return
                self.app.toast(self.status)

    def draw(self, surf):
        w.status_bar(surf, title="Pair new device", back=True)

        if not self.devices:
            msg = self.status if self.scan_done else "Looking for nearby devices…"
            title = fonts.render(t.Type.TITLE, msg, t.Color.TEXT_PRIMARY)
            surf.blit(title, (320 - title.get_width() // 2, 190))
            sub = fonts.render(t.Type.BODY_SM, "Put headphones or speakers into pairing mode.", t.Color.TEXT_SECONDARY)
            surf.blit(sub, (320 - sub.get_width() // 2, 220))

        for i, dev in enumerate(self.devices[:4]):
            rect = pygame.Rect(ROW_X, ROW_Y[i], ROW_W, ROW_H)
            w.device_row(surf, rect, dev["name"], dev["sub"], dev["icon"], dev["rssi"], focused=(i == self.focus))

        # progress bar @ 386 + meta @ 402
        if self.pair_job:
            frac = self.job_progress
            meta = self.status
        elif self.scan_done:
            frac = 1.0
            meta = self.status
        else:
            elapsed_frac = min(self.elapsed / (SCAN_SECONDS * 1000), 0.96)
            frac = max(self.scan_progress, elapsed_frac)
            remain = max(0, SCAN_SECONDS - int(self.elapsed / 1000))
            meta = f"{len(self.devices)} devices · {remain}s remaining" if remain else "finishing scan…"
        w.progress_bar(surf, 16, 386, 608, frac)
        meta_l = fonts.render(t.Type.MONO_TECH, meta, t.Color.TEXT_SECONDARY)
        surf.blit(meta_l, (16, 400))
        meta_r = fonts.render(t.Type.CAPTION, "L bond · R info", t.Color.TEXT_MUTED)
        surf.blit(meta_r, (640 - 16 - meta_r.get_width(), 400))

        if self.scan_done and not self.devices:
            hints = [("A", "scan again"), ("B", "back")]
        else:
            hints = [("A", "pair"), ("B", "cancel")]
        w.footer_hints(surf, hints)
