"use client"; import { useEffect, useState } from "react"; import type { AiCityForecastPayload, AiCityForecastState, } from "@/components/dashboard/scan-terminal/types"; import { formatTemperatureValue } from "@/lib/temperature-utils"; function confidenceBadge(confidence: string | null, isEn: boolean) { const c = String(confidence || "").toLowerCase(); if (c === "high") return { label: isEn ? "High" : "高", tone: "high" }; if (c === "medium") return { label: isEn ? "Medium" : "中", tone: "medium" }; return { label: isEn ? "Low" : "低", tone: "low" }; } function useTransitionMarker(status: string, hasContent: boolean) { const [showUpdated, setShowUpdated] = useState(false); useEffect(() => { if (status === "ready" && hasContent) { setShowUpdated(true); const id = setTimeout(() => setShowUpdated(false), 4000); return () => clearTimeout(id); } }, [status, hasContent]); return showUpdated; } export function AiEvidencePanel({ aiBullets, aiCityForecast, aiForecast, aiPredictedMax, aiRangeLow, aiRangeHigh, aiConfidence, aiReadCompleteText, aiReadInProgressText, aiRuleEvidenceMode, aiRuleEvidenceText, debPrediction, fallbackAiReason, isEn, isHkoObservation, localModelSupportNote, localizedFinalJudgment, rawObservationText, tempSymbol, }: { aiBullets: string[]; aiCityForecast: AiCityForecastPayload["city_forecast"] | null; aiForecast: AiCityForecastState; aiPredictedMax: number | null; aiRangeLow: number | null; aiRangeHigh: number | null; aiConfidence: string | null; aiReadCompleteText: string; aiReadInProgressText: string; aiRuleEvidenceMode: boolean; aiRuleEvidenceText: string; debPrediction: number | null; fallbackAiReason: string; isEn: boolean; isHkoObservation: boolean; localModelSupportNote: string; localizedFinalJudgment: string; rawObservationText: string; tempSymbol: string; }) { const aiConfidenceMeta = confidenceBadge(aiConfidence, isEn); const hasAiPrediction = aiPredictedMax != null; const hasDebPrediction = debPrediction != null; const aiRangeText = aiRangeLow != null && aiRangeHigh != null ? `${formatTemperatureValue(aiRangeLow, tempSymbol, { digits: 0 })} ~ ${formatTemperatureValue(aiRangeHigh, tempSymbol, { digits: 0 })}` : null; const showUpdatedBadge = useTransitionMarker(aiForecast.status, Boolean(aiCityForecast)); return (
{isHkoObservation ? isEn ? "Evidence · AI HKO observation read" : "证据 · AI 香港天文台观测解读" : isEn ? "Evidence · AI airport read" : "证据 · AI 机场报文解读"}
{hasAiPrediction || hasDebPrediction ? (
{hasAiPrediction ? (
{isEn ? "AI predicted high" : "AI 预测最高温"} {formatTemperatureValue(aiPredictedMax!, tempSymbol, { digits: 1 })} {aiConfidenceMeta.label} {aiRangeText ? {aiRangeText} : null}
) : aiForecast.status === "loading" && hasDebPrediction ? (
{isEn ? "AI predicted high" : "AI 预测最高温"} {isEn ? "..." : "…"} {isEn ? "Predicting" : "预测中"}
) : null} {hasDebPrediction ? (
{isEn ? "DEB fusion" : "DEB 融合"} {formatTemperatureValue(debPrediction!, tempSymbol, { digits: 1 })} {isEn ? "Reference" : "参考"}
) : null}
) : hasDebPrediction ? (
{isEn ? "DEB fusion" : "DEB 融合"} {formatTemperatureValue(debPrediction!, tempSymbol, { digits: 1 })} {isEn ? "Reference" : "参考"}
{isEn ? "AI predicted high" : "AI 预测最高温"} {isEn ? "..." : "…"} {isEn ? "Predicting" : "预测中"}
) : null} {aiForecast.status === "loading" ? ( <>

{aiReadInProgressText}

{localizedFinalJudgment || aiForecast.streamText ? (

{localizedFinalJudgment || aiForecast.streamText}

) : null}

{isEn ? isHkoObservation ? "Rule evidence is shown first; the full HKO AI read will merge automatically." : "Rule evidence is shown first; the full airport AI read will merge automatically." : isHkoObservation ? "先展示规则证据,完整香港天文台 AI 解读返回后会自动合并。" : "先展示规则证据,完整机场 AI 解读返回后会自动合并。"}

) : aiForecast.status === "ready" && aiCityForecast ? ( <> {showUpdatedBadge ? ( {isEn ? "✓ Updated" : "✓ 已更新"} ) : null}

{aiRuleEvidenceMode ? aiRuleEvidenceText : aiReadCompleteText}

{rawObservationText}

) : aiForecast.status === "ready" ? ( <>

{aiRuleEvidenceText}

) : aiForecast.status === "failed" ? ( <>

{aiRuleEvidenceText}

) : (

{isEn ? isHkoObservation ? "Waiting for AI to read the latest HKO observation." : "Waiting for AI to read the latest airport bulletin." : isHkoObservation ? "等待 AI 解读最新香港天文台观测。" : "等待 AI 解读最新机场报文。"}

)}
); }