#!/usr/bin/env python3
"""LANDR Live — clean Kandi stack. Pro master = same as DAW file path."""
from __future__ import annotations

import faulthandler
import sys
import threading
import time
from pathlib import Path

import numpy as np

ROOT = Path(__file__).resolve().parent
sys.path.insert(0, str(ROOT))

from kandi_audio import Duplex
from kandi_devices import pick_in, pick_out
from kandi_master import Master
from kandi_ui import Frame, UI, dbfs

DETECT_DB = -52.0
METER_N = 1024


def main() -> int:
    crash = ROOT / "LIVE_CRASH.log"
    try:
        faulthandler.enable(open(crash, "ab"))
    except OSError:
        faulthandler.enable()

    in_dev, in_name = pick_in()
    out_dev, out_name = pick_out()
    meter_in = np.zeros(METER_N, np.float32)
    meter_out = np.zeros(METER_N, np.float32)
    meter_lock = threading.Lock()
    ui = UI()
    master = Master(load_now=False)
    ui.draw(
        Frame(
            in_name=in_name,
            out_name=out_name,
            master_label="Twin master",
            bypass=False,
            engine_on=False,
            signal=False,
            in_db=-60.0,
            out_db=-60.0,
            pair=0,
            err="",
        )
    )
    master.bypass = "--bypass" in sys.argv

    duplex: Duplex | None = None
    err = ""
    signal = False
    lock_sent = False
    last_hit = 0.0

    def on_meter(in_mono: np.ndarray, out_mono: np.ndarray) -> None:
        with meter_lock:
            k = min(len(in_mono), METER_N)
            meter_in[:-k] = meter_in[k:]
            meter_in[-k:] = in_mono[-k:]
            k2 = min(len(out_mono), METER_N)
            meter_out[:-k2] = meter_out[k2:]
            meter_out[-k2:] = out_mono[-k2:]

    def on_process(stereo: np.ndarray, sr: float) -> np.ndarray:
        return master.process(stereo, sr)

    try:
        duplex = Duplex(in_dev, out_dev, in_name, on_process, on_meter)
    except RuntimeError as e:
        err = str(e)

    running = True
    while running:
        cmd = ui.poll()
        if cmd == "quit":
            running = False
        elif cmd == "bypass":
            master.bypass = not master.bypass
        with meter_lock:
            snap_in = meter_in.copy()
            snap_out = meter_out.copy()
        rms = float(np.sqrt(np.mean(snap_in * snap_in) + 1e-18))
        peak_in = float(np.max(np.abs(snap_in)) + 1e-18)
        peak_out = float(np.max(np.abs(snap_out)) + 1e-18)
        if dbfs(rms) > DETECT_DB or dbfs(peak_in) > DETECT_DB:
            signal = True
            last_hit = time.time()
            if not lock_sent:
                lock_sent = True
                threading.Thread(
                    target=Master.notify,
                    args=("LANDR Live", "Signal lock"),
                    daemon=True,
                ).start()
        elif time.time() - last_hit > 0.4:
            signal = False

        try:
            ui.draw(
                Frame(
                    in_name=in_name,
                    out_name=out_name,
                    master_label=master.label,
                    bypass=master.bypass,
                    engine_on=duplex is not None,
                    signal=signal,
                    in_db=dbfs(peak_in),
                    out_db=dbfs(peak_out),
                    pair=duplex.pair if duplex else 0,
                    err=err or (duplex.err if duplex else ""),
                    wave_in=snap_in,
                    wave_out=snap_out,
                )
            )
        except Exception:
            time.sleep(0.02)

    if duplex:
        duplex.close()
    ui.close()
    return 0


if __name__ == "__main__":
    try:
        raise SystemExit(main())
    except KeyboardInterrupt:
        raise SystemExit(0)
    except Exception:
        crash = ROOT / "LIVE_CRASH.log"
        import traceback

        crash.write_text(traceback.format_exc(), encoding="utf-8")
        raise
