"use client"; import clsx from "clsx"; import { ChevronDown, RefreshCw, X } from "lucide-react"; import type { MouseEvent } from "react"; import type { MarketDecisionView, WeatherDecisionView, } from "@/components/dashboard/scan-terminal/city-card-decision-utils"; import type { AiCityForecastPayload, AiCityForecastState, } from "@/components/dashboard/scan-terminal/types"; type StatusTone = "green" | "blue" | "amber" | "red" | "muted"; export type CityStatusTag = { label: string; tone: StatusTone; }; export type DataFreshnessRow = { label: string; value: string; tone: string; }; export function CityCardHeader({ aiStatusLabel, aiStatusTone, collapseId, collapsed, currentTempText, dataFreshnessRows, debText, detailLocalTime, displayName, expectedHighText, freshnessSeparator, isEn, isRefreshing, modelRange, onRefresh, onRemove, onToggleCollapsed, peakWindow, removing, rowLocalTime, statusTags, }: { aiStatusLabel: string; aiStatusTone: StatusTone; collapseId: string; collapsed: boolean; currentTempText: string; dataFreshnessRows: DataFreshnessRow[]; debText: string; detailLocalTime?: string | null; displayName: string; expectedHighText: string; freshnessSeparator: string; isEn: boolean; isRefreshing: boolean; modelRange: string; onRefresh: (event: MouseEvent) => void; onRemove: (event: MouseEvent) => void; onToggleCollapsed: () => void; peakWindow: string; removing?: boolean; rowLocalTime?: string | null; statusTags: CityStatusTag[]; }) { return (
{isEn ? "Deep analysis" : "城市深度分析"}

{displayName}

{isEn ? "Observed" : "当前温度"} {currentTempText} {isEn ? "Expected high" : "预测高点"} {expectedHighText} {isEn ? "Peak" : "峰值时间"} {peakWindow}
{statusTags.map((tag) => ( {tag.label} ))}
{detailLocalTime || rowLocalTime || "--"} DEB {debText} {isEn ? "Model" : "模型"} {modelRange} {isEn ? "Peak" : "峰值"} {peakWindow}
{isEn ? "Data freshness" : "数据新鲜度"} {dataFreshnessRows.map((freshness) => ( {freshness.label}{freshnessSeparator} {freshness.value} ))} AI{freshnessSeparator} {aiStatusLabel}
{isEn ? "Expected high" : "预计最高温"} {expectedHighText}
); } export function WeatherDecisionBand({ currentTempText, decisionView, decisionWhyText, isEn, longText, marketDecisionView, marketLineText, paceDeltaText, peakWindow, }: { currentTempText: string; decisionView: WeatherDecisionView; decisionWhyText: string; isEn: boolean; longText: string; marketDecisionView: MarketDecisionView; marketLineText: string; paceDeltaText: string; peakWindow: string; }) { return (
{decisionView.kicker} {decisionView.action}

{decisionWhyText}

{longText}

{decisionView.reasons.map((reason, index) => ( {reason} ))}

{decisionView.risk}

{isEn ? "Market price" : "市场价格"} {marketLineText}
{isEn ? "Polymarket price layer" : "Polymarket 价格层"} {marketDecisionView.title}

{marketDecisionView.reason}

{isEn ? "Bucket" : "温度桶"} {marketDecisionView.bucketLabel} {isEn ? "YES buy" : "YES 买价"} {marketDecisionView.priceText} {isEn ? "Model-market" : "模型-市场差"} {marketDecisionView.edgeText}
{marketDecisionView.marketUrl ? ( {isEn ? "Open market" : "打开市场"} ) : null}
{isEn ? "Expected high" : "预计高点"} {decisionView.expectedHigh} {isEn ? "Weather range" : "天气区间"} {decisionView.targetRange} {isEn ? "Confidence" : "信心"} {decisionView.confidence} {isEn ? "Observed" : "实测"} {currentTempText} {isEn ? "Path delta" : "路径偏差"} {paceDeltaText} {isEn ? "Peak window" : "峰值窗口"} {peakWindow} {isEn ? "Market implied" : "市场隐含"} {marketDecisionView.impliedText} {isEn ? "Model prob" : "模型概率"} {marketDecisionView.modelText} {isEn ? "Quote status" : "报价状态"}{" "} {marketDecisionView.status === "ready" ? (isEn ? "Ready" : "已同步") : marketDecisionView.status === "loading" ? (isEn ? "Loading" : "同步中") : (isEn ? "Unavailable" : "不可用")}
); } export function AiEvidencePanel({ aiBullets, aiCityForecast, aiForecast, aiReadCompleteText, aiReadInProgressText, aiRuleEvidenceMode, aiRuleEvidenceText, fallbackAiReason, isCompactCard, isEn, isHkoObservation, localModelSupportNote, localizedFinalJudgment, rawObservationText, }: { aiBullets: string[]; aiCityForecast: AiCityForecastPayload["city_forecast"] | null; aiForecast: AiCityForecastState; aiReadCompleteText: string; aiReadInProgressText: string; aiRuleEvidenceMode: boolean; aiRuleEvidenceText: string; fallbackAiReason: string; isCompactCard: boolean; isEn: boolean; isHkoObservation: boolean; localModelSupportNote: string; localizedFinalJudgment: string; rawObservationText: string; }) { return (
{isHkoObservation ? isEn ? "Evidence · AI HKO observation read" : "证据 · AI 香港天文台观测解读" : isEn ? "Evidence · AI airport read" : "证据 · AI 机场报文解读"}
{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 ? ( <>

{aiRuleEvidenceMode ? aiRuleEvidenceText : aiReadCompleteText}

    {[localizedFinalJudgment, ...aiBullets] .filter((line) => String(line || "").trim()) .map((line, index) => (
  • {line}
  • ))}

{rawObservationText}

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

{aiRuleEvidenceText}

    {fallbackAiReason ?
  • {fallbackAiReason}
  • : null}
  • {localModelSupportNote}
  • {rawObservationText}
) : aiForecast.status === "failed" ? ( <>

{aiRuleEvidenceText}

    {aiForecast.error ?
  • {aiForecast.error}
  • : null}
  • {localModelSupportNote}
  • {rawObservationText}
) : (

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

)}
); }