"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import { useAuth } from "@/hooks/useAuth";
import { TokenManager } from "@/lib/auth/tokenManager";
import "@/styles/mobile-alarm.css";

type Severity = "CRITICAL" | "WARNING" | "INFO";

type AlarmPayload = {
  code: string;
  severity: Severity;
  title: string;
  message: string;
  location: string;
  comp?: string;
  ts: number;
};

const MOCK_ALARM: AlarmPayload = {
  code: "P-IN-HH",
  severity: "CRITICAL",
  title: "BW-A1 펌프 과압 / 누설 의심",
  message:
    "BW-A1 토출 압력이 정상 운전 범위(4.0~5.0 bar)를 초과했습니다.\n현장 점검이 즉시 필요합니다.",
  location: "펌프룸 A · BW-A1 (원수 취수펌프 #1)",
  comp: "bw-a1",
  ts: 0,
};

const RECONNECT_DELAY_MS = 3000;

// Wake Lock API — 표준이지만 일부 브라우저에서 미지원이라 옵셔널 체이닝.
type WakeLockSentinel = { release: () => Promise<void> } & EventTarget;
type WakeLockNavigator = Navigator & {
  wakeLock?: { request: (type: "screen") => Promise<WakeLockSentinel> };
};

export function MobileAlarmClient() {
  const { user } = useAuth();
  const [mode, setMode] = useState<"idle" | "alarm">("idle");
  const [alarm, setAlarm] = useState<AlarmPayload | null>(null);
  const [clock, setClock] = useState("--:--:--");
  const [connected, setConnected] = useState(false);

  const wakeLockRef = useRef<WakeLockSentinel | null>(null);
  const audioCtxRef = useRef<AudioContext | null>(null);

  // ─── 시계 ────────────────────────────────────────────────────────
  useEffect(() => {
    const tick = () => {
      const d = new Date();
      const hh = String(d.getHours()).padStart(2, "0");
      const mm = String(d.getMinutes()).padStart(2, "0");
      const ss = String(d.getSeconds()).padStart(2, "0");
      setClock(`${hh}:${mm}:${ss}`);
    };
    tick();
    const t = setInterval(tick, 1000);
    return () => clearInterval(t);
  }, []);

  // ─── 알람음 (Web Audio API 비프, 외부 파일 의존성 없음) ───────────
  const playAlarmBeep = useCallback(() => {
    try {
      let ctx = audioCtxRef.current;
      if (!ctx) {
        const Ctor = (window.AudioContext || (window as unknown as { webkitAudioContext: typeof AudioContext }).webkitAudioContext);
        ctx = new Ctor();
        audioCtxRef.current = ctx;
      }
      // iOS 등은 사용자 제스처 없이 시작된 ctx 가 suspended 상태일 수 있음
      if (ctx.state === "suspended") void ctx.resume();
      const now = ctx.currentTime;
      // 3회 반복 비프 (650Hz / 0.18s on, 0.12s off)
      for (let i = 0; i < 3; i++) {
        const osc = ctx.createOscillator();
        const gain = ctx.createGain();
        osc.type = "square";
        osc.frequency.value = 650;
        const start = now + i * 0.3;
        const stop = start + 0.18;
        gain.gain.setValueAtTime(0.0001, start);
        gain.gain.exponentialRampToValueAtTime(0.35, start + 0.01);
        gain.gain.exponentialRampToValueAtTime(0.0001, stop);
        osc.connect(gain).connect(ctx.destination);
        osc.start(start);
        osc.stop(stop + 0.02);
      }
    } catch {
      // 오디오 실패해도 알람 표시는 정상 동작 — silent fail
    }
  }, []);

  // ─── 알람 표시 ───────────────────────────────────────────────────
  const showAlarm = useCallback(
    (payload: AlarmPayload) => {
      setAlarm({ ...payload, ts: payload.ts || Date.now() });
      setMode("alarm");
      if (typeof navigator !== "undefined" && navigator.vibrate) {
        navigator.vibrate([400, 120, 400, 120, 800]);
      }
      playAlarmBeep();
    },
    [playAlarmBeep],
  );

  const ackAlarm = useCallback(() => {
    setMode("idle");
    setAlarm(null);
    if (typeof navigator !== "undefined" && navigator.vibrate) {
      navigator.vibrate(0);
    }
  }, []);

  // ─── Wake Lock (화면 잠금 회피) ───────────────────────────────────
  useEffect(() => {
    const nav = navigator as WakeLockNavigator;
    if (!nav.wakeLock) return;

    const acquire = async () => {
      try {
        if (wakeLockRef.current) return;
        wakeLockRef.current = await nav.wakeLock!.request("screen");
        wakeLockRef.current.addEventListener("release", () => {
          wakeLockRef.current = null;
        });
      } catch {
        // 사용자 권한 없거나 미지원 — 무시
      }
    };

    void acquire();

    // 탭 복귀 시 lock 이 풀려있을 수 있으므로 재획득
    const onVisibility = () => {
      if (document.visibilityState === "visible") void acquire();
    };
    document.addEventListener("visibilitychange", onVisibility);

    return () => {
      document.removeEventListener("visibilitychange", onVisibility);
      void wakeLockRef.current?.release().catch(() => {});
      wakeLockRef.current = null;
    };
  }, []);

  // ─── WebSocket 연결 (auto reconnect) ─────────────────────────────
  useEffect(() => {
    if (typeof window === "undefined") return;
    const token = TokenManager.getToken();
    if (!token) return;

    const proto = window.location.protocol === "https:" ? "wss" : "ws";
    // /api/demo/* 는 시연 전용 path. 운영 Traefik 의 PathPrefix(`/api`) 라우트로 backend 까지 도달.
    const url = `${proto}://${window.location.host}/api/demo/ws/alarm?token=${encodeURIComponent(token)}`;

    let ws: WebSocket | null = null;
    let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
    let cancelled = false;

    const connect = () => {
      if (cancelled) return;
      ws = new WebSocket(url);

      ws.onopen = () => setConnected(true);
      ws.onclose = () => {
        setConnected(false);
        if (!cancelled) {
          reconnectTimer = setTimeout(connect, RECONNECT_DELAY_MS);
        }
      };
      ws.onerror = () => {
        // close 이벤트가 곧 따라옴 — 거기서 재연결 처리
      };
      ws.onmessage = (e) => {
        try {
          const data = JSON.parse(e.data);
          if (data?.type === "alarm" && data?.payload) {
            showAlarm(data.payload as AlarmPayload);
          }
        } catch {
          // 파싱 실패는 silent
        }
      };
    };

    connect();

    return () => {
      cancelled = true;
      if (reconnectTimer) clearTimeout(reconnectTimer);
      if (ws && ws.readyState <= 1) ws.close();
    };
  }, [showAlarm]);

  // ─── 시연 안전망 — ?test=1 자동 발동 ──────────────────────────────
  useEffect(() => {
    if (typeof window === "undefined") return;
    const params = new URLSearchParams(window.location.search);
    if (params.get("test") === "1") {
      const t = setTimeout(() => showAlarm(MOCK_ALARM), 800);
      return () => clearTimeout(t);
    }
  }, [showAlarm]);

  return (
    <div className={`m-shell ${mode === "alarm" ? "m-shell-alarm" : ""}`}>
      <header className="m-head">
        <span className="m-brand">🛡 INVYONE EHS</span>
        <span className={`m-conn ${connected ? "ok" : "off"}`}>
          <span className="m-dot" />
          {connected ? "실시간 연결됨" : "오프라인 (재연결 중...)"}
        </span>
      </header>

      {mode === "idle" && (
        <main className="m-idle">
          <div className="m-glow-orb" />
          <div className="m-clock">{clock}</div>
          <div className="m-user">{user?.user_name ?? "작업자"}</div>
          {user?.dept_name && <div className="m-user-dept">{user.dept_name}</div>}
          <div className="m-idle-hint">
            설비 알람이 발생하면 진동과 함께
            <br />이 화면에 풀스크린으로 표시됩니다
          </div>
        </main>
      )}

      {mode === "alarm" && alarm && (
        <main className="m-alarm">
          <div className="m-alarm-bg" />
          <div className="m-alarm-card">
            <div className="m-alarm-sev">{alarm.severity}</div>
            <div className="m-alarm-icon">⚠</div>
            <div className="m-alarm-code">{alarm.code}</div>
            <div className="m-alarm-title">{alarm.title}</div>
            <div className="m-alarm-loc">📍 {alarm.location}</div>
            <div className="m-alarm-msg">{alarm.message}</div>
            <div className="m-alarm-actions">
              <button className="m-btn-ack" onClick={ackAlarm}>
                ✓ 확인 (ACK) — 현장 출동
              </button>
              <button className="m-btn-skip" onClick={ackAlarm}>
                나중에
              </button>
            </div>
            <div className="m-alarm-time">
              발생: {new Date(alarm.ts).toLocaleTimeString("ko-KR")}
            </div>
          </div>
        </main>
      )}

      {/* 시연 안전망 — 우상단 점 클릭으로 mock 알람 트리거 */}
      <button
        className="m-test-trigger"
        onClick={() => (mode === "idle" ? showAlarm(MOCK_ALARM) : ackAlarm())}
        aria-label="test trigger"
        title="test trigger"
      />
    </div>
  );
}
