import { useEffect, useMemo, useState } from "react";
import { useTimeSkew } from "../hooks/useTimeSkew";
import { config } from "../config";

function formatDelay(ms: number, withSign = true) {
    const sign = withSign ? (ms > 0 ? "+" : ms < 0 ? "−" : "") : "";
    const abs = Math.abs(ms);
    if (abs >= 1000) {
        const s = Math.floor(abs / 1000);
        const rem = abs % 1000;
        return `${sign}${s}s${rem ? ` ${rem}ms` : ""}`;
    }
    return `${sign}${abs}ms`;
}

export default function TimeSyncNotice({
    thresholdMs = 500,
    intervalMs,
    lang = "ja",
    dismissTtlMs = 5 * 60_000, // ✅ reappear after 5 minutes by default
    storageScope = "session",   // "session" | "local"
}: {
    thresholdMs?: number;
    intervalMs?: number;
    lang?: "ja" | "en";
    dismissTtlMs?: number;
    storageScope?: "session" | "local";
}) {
    const { skewMs, rttMs, recheck, error } = useTimeSkew({ intervalMs: intervalMs ?? config.intervals.timeSkewMs });

    const KEY = "timesync.dismissedUntil";
    const store = useMemo(
        () => (storageScope === "local" ? window.localStorage : window.sessionStorage),
        [storageScope],
    );

    // read dismissed state (true if now < dismissedUntil)
    const [dismissed, setDismissed] = useState<boolean>(() => {
        try {
            const raw = store.getItem(KEY);
            const until = raw ? Number(raw) : 0;
            return Number.isFinite(until) && Date.now() < until;
        } catch {
            return false;
        }
    });

    // auto-unset when TTL passes (while component stays mounted)
    useEffect(() => {
        if (!dismissed) return;
        let id: number | null = null;
        try {
            const raw = store.getItem(KEY);
            const until = raw ? Number(raw) : 0;
            const delay = Math.max(0, until - Date.now());
            if (delay > 0) {
                id = window.setTimeout(() => setDismissed(false), delay);
            } else {
                setDismissed(false);
                store.removeItem(KEY);
            }
        } catch {
            // ignore storage errors
        }
        return () => { if (id) clearTimeout(id); };
    }, [dismissed, store]);

    // if skew returns within threshold, clear dismissal so it can show again later if it drifts
    useEffect(() => {
        if (skewMs != null && Math.abs(skewMs) <= thresholdMs && dismissed) {
            setDismissed(false);
            try { store.removeItem(KEY); } catch { void 0; }
        }
    }, [skewMs, thresholdMs, dismissed, store]);

    if (dismissed) return null;

    const hasSkew = skewMs != null;
    const skewVal = skewMs ?? 0;
    if (!error && (!hasSkew || Math.abs(skewVal) <= thresholdMs)) return null;

    const ahead = skewVal > 0;
    const msgJa = error
        ? `時刻同期に失敗しました: ${error}`
        : ahead
            ? `端末の時計が正確な時刻より ${formatDelay(skewVal)} 進んでいます（通信往復遅延 ${rttMs ?? "-"}ms）`
            : `端末の時計が正確な時刻より ${formatDelay(-skewVal)} 遅れています（通信往復遅延 ${rttMs ?? "-"}ms）`;
    const msgEn = error
        ? `Time sync failed: ${error}`
        : ahead
            ? `Your device clock is ${formatDelay(skewVal)} ahead of the correct time (RTT ${rttMs ?? "-"}ms).`
            : `Your device clock is ${formatDelay(-skewVal)} behind the correct time (RTT ${rttMs ?? "-"}ms).`;

    const onClose = () => {
        setDismissed(true);
        try {
            const until = Date.now() + dismissTtlMs;
            store.setItem(KEY, String(until));
        } catch {
            // ignore storage failures
        }
    };

    return (
        <div className="timesync-banner" role="status" aria-live="polite">
            <div className="timesync-msg">{lang === "ja" ? msgJa : msgEn}</div>
            <div className="timesync-actions">
                <button className="timesync-btn" onClick={() => recheck?.()}>
                    {lang === "ja" ? "再測定" : "Re-check"}
                </button>
                <button className="timesync-close" onClick={onClose} aria-label={lang === "ja" ? "閉じる" : "Close"}>
                    ×
                </button>
            </div>
        </div>
    );
}
