// InfoScreen2.tsx 此页面为桨频器信息页面
import React, { useEffect, useRef, useState } from "react";
import {
  ActivityIndicator,
  Pressable,
  ScrollView,
  StyleSheet,
  Text,
  View,
  Alert,
} from "react-native";
import { NativeStackScreenProps } from "@react-navigation/native-stack";
import { decode as atob } from "base-64";
import {
  Central,
  ScannedPeripheral,
  ConnectionStatus,
} from "@systemic-games/react-native-bluetooth-le";
import { RootStackParamList } from "../App";
import { useTranslation } from "react-i18next";
import MyStatusbar from "./component/MyStatusbar";
import MyHeader from "./component/MyHeader";

type Props = NativeStackScreenProps<RootStackParamList, "Info2">;

const CSC_SERVICE_UUID = "1816";
const CSC_MEASUREMENT_UUID = "2a5b";

const CUSTOM_SERVICE_UUID = "fff1";
const CUSTOM_WRITE_UUID = "fff2";
const CUSTOM_NOTIFY_UUID = "fff3";

const DFU_MANIFEST_URL =
  "https://powerfun.oss-cn-shanghai.aliyuncs.com/yecongdfu/latest.json";

type BoatType = 0x00 | 0x01 | 0x02;

type ParsedFirmware = {
  hardware: number;
  iteration: number;
  build: string;
  raw: string;
};

type DeviceInfo = {
  hardware: number;
  latestFirmware: string;
  download: string;
};

const fullUUID = (uuid: string) =>
  uuid.length === 4
    ? `0000${uuid}-0000-1000-8000-00805f9b34fb`
    : uuid;

const sleep = (ms: number) =>
  new Promise<void>((resolve) => setTimeout(resolve, ms));

const base64ToBytes = (base64: string): number[] => {
  const binary = atob(base64);
  const bytes: number[] = [];

  for (let i = 0; i < binary.length; i += 1) {
    bytes.push(binary.charCodeAt(i) & 0xff);
  }

  return bytes;
};

const bytesToArrayBuffer = (bytes: number[]): ArrayBuffer => {
  return new Uint8Array(bytes).buffer;
};

const normalizeBytes = (arr: number[]): number[] => {
  return arr.map((v) => v & 0xff);
};

const toHexByte = (value: number): string =>
  (value & 0xff).toString(16).toUpperCase().padStart(2, "0");

const bytesToHexString = (bytes: number[]): string =>
  normalizeBytes(bytes)
    .map((v) => toHexByte(v))
    .join(" ");

const parseFirmwareVersion = (text: string): ParsedFirmware => {
  const raw = String(text ?? "").trim();
  const parts = raw.split(".");

  if (parts.length < 2) {
    throw new Error(`固件版本格式不正确: ${raw}`);
  }

  const hardware = parseInt(parts[0], 10);
  const iteration = parseInt(parts[1], 10);
  const build = parts.length >= 3 ? parts[2] : "";

  if (Number.isNaN(hardware) || Number.isNaN(iteration)) {
    throw new Error(`固件版本无法解析: ${raw}`);
  }

  return {
    hardware,
    iteration,
    build,
    raw,
  };
};

export default function InfoScreen2({ route, navigation }: Props) {
  const { t } = useTranslation();
  const { peripheral } = route.params;
  const getBoatNameByValue = (value?: number | null): string => {
    if (value === 0x00) return t("info2.boatKayak");
    if (value === 0x01) return t("info2.boatRowing");
    if (value === 0x02) return t("info2.boatRacing");
    return t("common.unknown");
  };

  const deviceKey =
    typeof peripheral.address === "string" && peripheral.address.length > 0
      ? peripheral.address
      : String(peripheral.systemId ?? "");

  const [cadence, setCadence] = useState(0);
  const [isLoading, setIsLoading] = useState(true);

  const [selectedBoat, setSelectedBoat] = useState<BoatType | null>(0x00);
  const [boatBusy, setBoatBusy] = useState(false);
  const [boatStatus, setBoatStatus] = useState(t("info2.waitingAction"));
  const [boatNotifyHex, setBoatNotifyHex] = useState("--");
  const [boatVerified, setBoatVerified] = useState("--");

  const [isConnected, setIsConnected] = useState(false);
  const [serial, setSerial] = useState(t("info.reading"));
  const [firmware, setFirmware] = useState(t("info.reading"));
  const [battery, setBattery] = useState(t("info.reading"));

  // 新增：固件升级状态
  const [latestFirmware, setLatestFirmware] = useState(t("info.reading"));
  const [upgradeAvailable, setUpgradeAvailable] = useState(false);
  const [upgradeCheckDone, setUpgradeCheckDone] = useState(false);

  const lastCrankRef = useRef<number | null>(null);
  const lastEventTimeRef = useRef<number | null>(null);
  const lastCadenceUpdateAppTsRef = useRef<number | null>(null);

  const boatReadResolverRef = useRef<((bytes: number[]) => void) | null>(null);
  const mountedRef = useRef(true);
  const disconnectingRef = useRef(false);

  const hasConnectedOnceRef = useRef(false);
  const hasNavigatedBackRef = useRef(false);
  const skipDisconnectOnLeaveRef = useRef(false);

  const checkUpgradeNeeded = async (firmwareText: string) => {
    try {
      const text = String(firmwareText ?? "").trim();

      if (!text) {
        if (mountedRef.current) {
          setLatestFirmware(t("common.unknown"));
          setUpgradeAvailable(false);
          setUpgradeCheckDone(true);
        }
        return;
      }

      const currentFw = parseFirmwareVersion(text);
      console.log("🔥 InfoScreen currentFw =", currentFw);

      const manifestResp = await fetch(DFU_MANIFEST_URL);
      console.log("🔥 InfoScreen manifest status =", manifestResp.status);

      if (!manifestResp.ok) {
        throw new Error(`manifest 下载失败，HTTP ${manifestResp.status}`);
      }

      const manifestText = await manifestResp.text();
      console.log("🔥 InfoScreen manifest text =", manifestText);

      let manifest: { devices: DeviceInfo[] };

      try {
        manifest = JSON.parse(manifestText) as { devices: DeviceInfo[] };
      } catch (e) {
        throw new Error("manifest 不是合法 JSON");
      }

      const deviceInfo = manifest.devices.find(
        (d) => d.hardware === currentFw.hardware
      );

      console.log("🔥 InfoScreen matched deviceInfo =", deviceInfo);

      if (!deviceInfo) {
        if (mountedRef.current) {
          setLatestFirmware(t("info2.notMatched"));
          setUpgradeAvailable(false);
          setUpgradeCheckDone(true);
        }
        return;
      }

      const latestFw = parseFirmwareVersion(deviceInfo.latestFirmware);
      console.log("🔥 InfoScreen latestFw =", latestFw);

      if (latestFw.hardware !== currentFw.hardware) {
        throw new Error(
          `服务器固件硬件号不匹配：当前 ${currentFw.hardware}，服务器 ${latestFw.hardware}`
        );
      }

      const needUpgrade = latestFw.iteration > currentFw.iteration;

      if (mountedRef.current) {
        setLatestFirmware(deviceInfo.latestFirmware);
        setUpgradeAvailable(needUpgrade);
        setUpgradeCheckDone(true);
      }
    } catch (err: any) {
      console.warn("⚠️ checkUpgradeNeeded failed:", err);
      if (mountedRef.current) {
        setLatestFirmware(t("info2.checkFailed"));
        setUpgradeAvailable(false);
        setUpgradeCheckDone(true);
      }
    }
  };

  const readDeviceInfo = async () => {
    console.log("📘 start read device info...");

    try {
      try {
        const v = await Central.readCharacteristic(
          peripheral,
          fullUUID("180a"),
          fullUUID("2a25")
        );

        if (v && (v as any).length) {
          const idText = String.fromCharCode(...(v as any));
          console.log("📘 serial raw:", v, "=>", idText);
          if (mountedRef.current) {
            setSerial(idText);
          }
        } else if (mountedRef.current) {
          setSerial(
            (peripheral.address ||
              peripheral.systemId ||
              peripheral.name ||
              t("common.unknown")) as string
          );
        }
      } catch (err) {
        console.warn("⚠️ read serial failed:", err);
        if (mountedRef.current) {
          setSerial(
            (peripheral.address ||
              peripheral.systemId ||
              peripheral.name ||
              t("common.unknown")) as string
          );
        }
      }

      try {
        const v = await Central.readCharacteristic(
          peripheral,
          fullUUID("180a"),
          fullUUID("2a28")
        );

        if (v && (v as any).length) {
          const fwText = String.fromCharCode(...(v as any));
          console.log("📘 firmware raw:", v, "=>", fwText);
          if (mountedRef.current) {
            setFirmware(fwText);
          }

          // 新增：在 Info 页提前检查是否需要升级
          await checkUpgradeNeeded(fwText);
        } else if (mountedRef.current) {
          setFirmware(t("common.unknown"));
          setLatestFirmware(t("common.unknown"));
          setUpgradeAvailable(false);
          setUpgradeCheckDone(true);
        }
      } catch (err) {
        console.warn("⚠️ read firmware failed:", err);
        if (mountedRef.current) {
          setFirmware(t("common.unknown"));
          setLatestFirmware(t("common.unknown"));
          setUpgradeAvailable(false);
          setUpgradeCheckDone(true);
        }
      }

      try {
        const v = await Central.readCharacteristic(
          peripheral,
          fullUUID("180f"),
          fullUUID("2a19")
        );

        if (v && (v as any).length) {
          const batteryValue = (v as any)[0];
          console.log("📘 battery raw:", v, "=>", batteryValue);
          if (mountedRef.current) {
            setBattery(`${batteryValue}%`);
          }
        } else if (mountedRef.current) {
          setBattery(t("common.unknown"));
        }
      } catch (err) {
        console.warn("⚠️ read battery failed:", err);
        if (mountedRef.current) {
          setBattery(t("common.unknown"));
        }
      }
    } catch (err) {
      console.warn("⚠️ readDeviceInfo failed:", err);
      if (mountedRef.current) {
        setSerial(
          (peripheral.address ||
            peripheral.systemId ||
            peripheral.name ||
            t("common.unknown")) as string
        );
        setFirmware(t("common.unknown"));
        setBattery(t("common.unknown"));
        setLatestFirmware(t("common.unknown"));
        setUpgradeAvailable(false);
        setUpgradeCheckDone(true);
      }
    }
  };

  const writeBytesToFff2 = async (bytes: number[]) => {
    const normalized = normalizeBytes(bytes);
    const buffer = bytesToArrayBuffer(normalized);

    console.log("✍️ write FFF2 hex:", bytesToHexString(normalized));

    await Central.writeCharacteristic(
      peripheral,
      fullUUID(CUSTOM_SERVICE_UUID),
      fullUUID(CUSTOM_WRITE_UUID),
      buffer,
      { withoutResponse: false }
    );
  };

  const waitBoatNotifyOnce = (timeoutMs = 3000): Promise<number[]> => {
    return new Promise((resolve, reject) => {
      const timer = setTimeout(() => {
        if (boatReadResolverRef.current) {
          boatReadResolverRef.current = null;
        }
        reject(new Error(t("info2.waitFff3Timeout")));
      }, timeoutMs);

      boatReadResolverRef.current = (bytes: number[]) => {
        const normalized = normalizeBytes(bytes);

        if (normalized.length < 1) {
          console.log("⚠️ 忽略 FFF3：长度不足 1 字节");
          return;
        }

        clearTimeout(timer);
        boatReadResolverRef.current = null;
        resolve(normalized);
      };
    });
  };

  const applyBoatTypeFromNotify = (notifyBytes: number[]) => {
    let returnedBoatType: number | null = null;

    if (notifyBytes.length === 1) {
      returnedBoatType = notifyBytes[0];
    } else if (notifyBytes[0] === 0x01 && notifyBytes.length >= 2) {
      returnedBoatType = notifyBytes[1];
    } else {
      returnedBoatType = notifyBytes[0];
    }

    if (
      returnedBoatType === 0x00 ||
      returnedBoatType === 0x01 ||
      returnedBoatType === 0x02
    ) {
      setSelectedBoat(returnedBoatType as BoatType);
      setBoatVerified(
        t("info2.currentBoat", { boatName: getBoatNameByValue(returnedBoatType) })
      );
      setBoatStatus(
        t("info2.readCurrentBoat", {
          boatName: getBoatNameByValue(returnedBoatType),
        })
      );
      console.log(
        "🚣 apply boat type:",
        returnedBoatType,
        getBoatNameByValue(returnedBoatType)
      );
    } else {
      setBoatVerified(`❌ ${t("info2.unknownBoatType")}`);
      setBoatStatus(t("info2.readAbnormal", { hex: bytesToHexString(notifyBytes) }));
      console.log("⚠️ unknown boat notify:", bytesToHexString(notifyBytes));
    }
  };

  const handleSetBoatType = async (boatType: BoatType) => {
    if (boatBusy) return;

    try {
      setBoatBusy(true);
      setBoatVerified("--");
      setBoatNotifyHex("--");

      const boatName = getBoatNameByValue(boatType);

      setBoatStatus(t("info2.writingBoat", { boatName }));
      await writeBytesToFff2([0x01, boatType]);

      setBoatStatus(t("info2.writtenWaitRead", { boatName }));
      await sleep(200);

      setBoatStatus(t("info2.requestingBoatRead"));
      const waitPromise = waitBoatNotifyOnce(3000);

      await writeBytesToFff2([0x02]);

      const notifyBytes = await waitPromise;
      const hex = bytesToHexString(notifyBytes);
      setBoatNotifyHex(hex);

      let returnedBoatType: number | null = null;

      if (notifyBytes.length === 1) {
        returnedBoatType = notifyBytes[0];
      } else if (notifyBytes[0] === 0x01) {
        returnedBoatType = notifyBytes[1];
      } else {
        returnedBoatType = notifyBytes[0];
      }

      const ok = returnedBoatType === boatType;

      if (ok) {
        applyBoatTypeFromNotify(notifyBytes);
        setBoatStatus(t("info2.setSuccess", { boatName }));
      } else {
        setBoatVerified(
          `❌ ${t("info2.notMatch", {
            expected: boatName,
            actual: getBoatNameByValue(returnedBoatType),
          })}`
        );
        setBoatStatus(t("info2.readResult", { hex }));
      }
    } catch (error: any) {
      console.warn("❌ set boat type failed:", error);
      setBoatStatus(
        t("info2.actionFailed", { message: error?.message ?? "unknown error" })
      );
      setBoatVerified(`❌ ${t("info2.failed")}`);
    } finally {
      setBoatBusy(false);
    }
  };

  const goToDfu = () => {
    if (!isConnected) {
      Alert.alert(t("common.notice"), t("info2.disconnectedNeedReconnect"), [
        {
          text: t("info.confirm"),
          onPress: () => {
            navigation.goBack();
          },
        },
      ]);
      return;
    }

    skipDisconnectOnLeaveRef.current = true;
    console.log("🔥 peripheral =", JSON.stringify(peripheral, null, 2));
    console.log("🔥 peripheral.address =", peripheral.address);
    console.log("🔥 peripheral.systemId =", peripheral.systemId);
    console.log("🔥 peripheral.id =", peripheral.id);
    console.log("🔥 peripheral.identifier =", peripheral.identifier);
    console.log("🔥 peripheral.uuid =", peripheral.uuid);
    console.log("🔥 current deviceKey =", deviceKey);

    navigation.navigate("Dfu", {
      deviceId: deviceKey,
      systemId: peripheral.systemId,
      address: peripheral.address,
      name: peripheral.name ?? "",
      firmware: firmware ?? "",
    });
  };

  useEffect(() => {
    const connectionHandler = async (ev: {
      peripheral: ScannedPeripheral;
      connectionStatus: ConnectionStatus;
    }) => {
      const addr = ev.peripheral.address || ev.peripheral.systemId;
      if (addr !== deviceKey) return;

      console.log("🔌 connection event:", ev.connectionStatus);

      const connected =
        ev.connectionStatus === "connected" || ev.connectionStatus === "ready";

      setIsConnected(connected);

      if (connected) {
        hasConnectedOnceRef.current = true;
        return;
      }

      if (
        hasConnectedOnceRef.current &&
        mountedRef.current &&
        !disconnectingRef.current &&
        !hasNavigatedBackRef.current
      ) {
        hasNavigatedBackRef.current = true;

        console.log("↩️ 检测到设备断开，自动返回上一级");

        if (navigation.canGoBack()) {
          navigation.goBack();
        }
      }
    };

    Central.addListener("peripheralConnectionStatus", connectionHandler);
    return () => {
      Central.removeListener("peripheralConnectionStatus", connectionHandler);
    };
  }, [deviceKey, navigation]);

  useEffect(() => {
    const unsubscribe = navigation.addListener("beforeRemove", async (e) => {
      if (disconnectingRef.current) return;
      disconnectingRef.current = true;

      const next = e.data.action?.type;
      const action = e.data.action as any;

      if (next === "NAVIGATE" && action?.payload?.name === "Dfu") {
        console.log("➡️ 跳转到 DFU，不断开蓝牙");
        disconnectingRef.current = false;
        return;
      }

      console.log("📴 页面关闭，断开蓝牙...");
      try {
        await Central.disconnectPeripheral(peripheral);
        console.log("✅ 已断开蓝牙");
      } catch (err) {
        console.warn("❌ 断开失败：", err);
      } finally {
        disconnectingRef.current = false;
      }
    });

    return unsubscribe;
  }, [navigation, peripheral]);

  useEffect(() => {
    mountedRef.current = true;

    let cscSubscription: any = null;
    let customSubscription: any = null;
    let cadenceZeroTimer: ReturnType<typeof setInterval> | null = null;

    const handleMeasurement = (ev: any) => {
      const rawData: number[] = Array.isArray(ev?.value)
        ? ev.value
        : typeof ev?.value === "string"
        ? base64ToBytes(ev.value)
        : ev?.value instanceof ArrayBuffer
        ? Array.from(new Uint8Array(ev.value))
        : [];

      const data = normalizeBytes(rawData);

      if (data.length === 0) {
        console.log("📥 CSC raw data: <empty>");
        return;
      }

      console.log("📥 CSC raw data hex:", bytesToHexString(data));

      if (data.length < 5) {
        console.log("⚠️ invalid CSC packet length:", data.length);
        return;
      }

      const flags = data[0];

      if (flags !== 0x02) {
        console.log("⚠️ unexpected CSC flags:", toHexByte(flags));
        return;
      }

      const crankRevolutions = data[1] | (data[2] << 8);
      const crankEventTime = data[3] | (data[4] << 8);

      const lastCrank = lastCrankRef.current;
      const lastEventTime = lastEventTimeRef.current;

      console.log(
        "📊 CSC parsed:",
        "crankRevolutions=",
        crankRevolutions,
        "crankEventTime=",
        crankEventTime,
        "lastCrank=",
        lastCrank,
        "lastEventTime=",
        lastEventTime
      );

      if (lastCrank !== null && lastEventTime !== null) {
        let deltaCrank = crankRevolutions - lastCrank;
        let deltaTime = crankEventTime - lastEventTime;

        if (deltaCrank < 0) deltaCrank += 0x10000;
        if (deltaTime < 0) deltaTime += 0x10000;

        console.log(
          "📊 CSC delta:",
          "deltaCrank=",
          deltaCrank,
          "deltaTime=",
          deltaTime
        );

        if (deltaCrank > 0 && deltaTime > 0) {
          if (deltaCrank <= 4) {
            const rpm = (60 * 1024 * deltaCrank) / deltaTime;

            console.log("📊 CSC rpm raw:", rpm);

            if (rpm >= 1 && rpm <= 220) {
              const roundedCadence = Math.round(rpm);
              const appNow = Date.now();

              if (mountedRef.current) {
                setCadence(roundedCadence);
              }

              lastCadenceUpdateAppTsRef.current = appNow;

              console.log(
                "✅ cadence updated:",
                "cadence=",
                roundedCadence,
                "appTs=",
                appNow,
                "bleCrank=",
                crankRevolutions,
                "bleEventTime=",
                crankEventTime
              );
            } else {
              console.log("⚠️ rpm out of range, ignored:", rpm);
            }
          } else {
            console.log("⚠️ deltaCrank too large, ignored:", deltaCrank);
          }
        } else {
          console.log(
            "⚠️ delta invalid, ignored:",
            "deltaCrank=",
            deltaCrank,
            "deltaTime=",
            deltaTime
          );
        }
      } else {
        console.log(
          "🟡 first valid CSC packet, baseline saved only:",
          "crankRevolutions=",
          crankRevolutions,
          "crankEventTime=",
          crankEventTime
        );
      }

      lastCrankRef.current = crankRevolutions;
      lastEventTimeRef.current = crankEventTime;
    };

    const handleBoatNotify = (ev: any) => {
      const rawData: number[] = Array.isArray(ev?.value)
        ? ev.value
        : typeof ev?.value === "string"
        ? base64ToBytes(ev.value)
        : ev?.value instanceof ArrayBuffer
        ? Array.from(new Uint8Array(ev.value))
        : [];

      const data = normalizeBytes(rawData);

      if (data.length === 0) {
        console.log("📥 FFF3 raw data: <empty>");
        return;
      }

      const hex = bytesToHexString(data);
      console.log("📥 FFF3 raw data hex:", hex);

      if (mountedRef.current) {
        setBoatNotifyHex(hex);
      }

      if (boatReadResolverRef.current) {
        boatReadResolverRef.current(data);
      }
    };

    (async () => {
      setIsLoading(true);

      try {
        await Central.connectPeripheral(peripheral);
        await new Promise<void>((resolve) => setTimeout(resolve, 500));
        setIsConnected(true);
        hasConnectedOnceRef.current = true;
        hasNavigatedBackRef.current = false;

        console.log("📡 subscribe CSC:", CSC_MEASUREMENT_UUID);
        cscSubscription = await Central.subscribeCharacteristic(
          peripheral,
          fullUUID(CSC_SERVICE_UUID),
          fullUUID(CSC_MEASUREMENT_UUID),
          handleMeasurement
        );

        console.log("📡 subscribe FFF3:", CUSTOM_NOTIFY_UUID);
        customSubscription = await Central.subscribeCharacteristic(
          peripheral,
          fullUUID(CUSTOM_SERVICE_UUID),
          fullUUID(CUSTOM_NOTIFY_UUID),
          handleBoatNotify
        );

        await readDeviceInfo();

        cadenceZeroTimer = setInterval(() => {
          const lastUpdateTs = lastCadenceUpdateAppTsRef.current;
          const now = Date.now();

          if (lastUpdateTs === null) {
            return;
          }

          const elapsed = now - lastUpdateTs;

          if (elapsed > 3000) {
            if (mountedRef.current) {
              setCadence((prev) => {
                if (prev !== 0) {
                  console.log(
                    "⏱️ cadence reset to 0 and baseline cleared:",
                    "now=",
                    now,
                    "lastCadenceUpdateAppTs=",
                    lastUpdateTs,
                    "elapsedMs=",
                    elapsed
                  );
                  return 0;
                }
                return prev;
              });
            }

            lastCrankRef.current = null;
            lastEventTimeRef.current = null;
            lastCadenceUpdateAppTsRef.current = null;
          }
        }, 500);

        console.log("✅ all subscribe success");

        try {
          console.log("🔎 default read boat type: write FFF2 = 02");
          const waitPromise = waitBoatNotifyOnce(3000);
          await writeBytesToFff2([0x02]);
          const notifyBytes = await waitPromise;

          if (mountedRef.current) {
            setBoatNotifyHex(bytesToHexString(notifyBytes));
            applyBoatTypeFromNotify(notifyBytes);
          }
        } catch (err) {
          console.warn("⚠️ default read boat type failed:", err);
          if (mountedRef.current) {
            setBoatStatus(t("info2.defaultReadFailed"));
          }
        }

        if (mountedRef.current) {
          setIsLoading(false);
        }
      } catch (e) {
        console.warn("❌ 读取失败", e);
        if (mountedRef.current) {
          setIsLoading(false);
          setIsConnected(false);
          setBoatStatus(t("info2.connectOrReadFailed"));
          Alert.alert(t("common.notice"), t("info2.connectOrReadFailedAlert"));
        }
      }
    })();

    return () => {
      mountedRef.current = false;
      hasConnectedOnceRef.current = false;
      hasNavigatedBackRef.current = false;
      setIsConnected(false);

      try {
        if (cscSubscription?.remove) {
          cscSubscription.remove();
        }
      } catch (err) {
        console.warn("⚠️ csc subscription remove failed:", err);
      }

      try {
        if (customSubscription?.remove) {
          customSubscription.remove();
        }
      } catch (err) {
        console.warn("⚠️ custom subscription remove failed:", err);
      }

      if (cadenceZeroTimer) {
        clearInterval(cadenceZeroTimer);
        cadenceZeroTimer = null;
      }

      boatReadResolverRef.current = null;
      lastCrankRef.current = null;
      lastEventTimeRef.current = null;
      lastCadenceUpdateAppTsRef.current = null;

      try {
        if (!skipDisconnectOnLeaveRef.current) {
          Central.disconnectPeripheral(peripheral);
        } else {
          console.log("➡️ cleanup: 跳转到 DFU，不断开蓝牙");
        }
      } catch {}
    };
  }, [peripheral]);

  return (
    <>
      <MyStatusbar backgroundColor="#f2f3f7" dark />
      <MyHeader
        title={t("info.title")}
        textColor="#333"
        backgroundColor="#f2f3f7"
        navigation={navigation}
      />
      <ScrollView
        style={styles.container}
        contentContainerStyle={styles.contentContainer}
        showsVerticalScrollIndicator={false}
      >
        {isLoading ? (
          <ActivityIndicator
            size="large"
            color="#E7141E"
            style={{ marginTop: 40 }}
          />
        ) : (
          <>
            {/* 1. 桨频数据框 */}
            <View style={styles.cadenceCard}>
              <Text style={styles.cadenceLabel}>{t("info2.cadence")}</Text>
              <Text style={styles.cadenceValue}>{cadence}</Text>
              <Text style={styles.cadenceUnit}>{t("info2.cadenceUnit")}</Text>
            </View>

            {/* 2. 船型选择 */}
            <View style={styles.sectionCard}>
              <View style={styles.sectionHeader}>
                <Text style={styles.sectionTitle}>{t("info2.boatSelect")}</Text>
                <View style={styles.statusContainer}>
                  {boatBusy ? (
                    <Text style={styles.statusTextBusy}>{t("info2.boatSwitching")}</Text>
                  ) : boatVerified.startsWith("✅") ? (
                    <Text style={styles.statusTextSuccess}>✅</Text>
                  ) : boatVerified.startsWith("❌") ? (
                    <Text style={styles.statusTextError}>❌{t("info2.retry")}</Text>
                  ) : (
                    <Text style={styles.statusText}>-</Text>
                  )}
                </View>
              </View>

              <View style={styles.buttonRow}>
                <Pressable
                  style={[
                    styles.boatButton,
                    selectedBoat === 0x00 && styles.boatButtonActive,
                  ]}
                  onPress={() => handleSetBoatType(0x00)}
                  disabled={boatBusy}
                >
                  <Text
                    style={[
                      styles.boatButtonText,
                      selectedBoat === 0x00 && styles.boatButtonTextActive,
                    ]}
                  >
                    {t("info2.boatKayak")}
                  </Text>
                </Pressable>

                <Pressable
                  style={[
                    styles.boatButton,
                    selectedBoat === 0x01 && styles.boatButtonActive,
                  ]}
                  onPress={() => handleSetBoatType(0x01)}
                  disabled={boatBusy}
                >
                  <Text
                    style={[
                      styles.boatButtonText,
                      selectedBoat === 0x01 && styles.boatButtonTextActive,
                    ]}
                  >
                    {t("info2.boatRowing")}
                  </Text>
                </Pressable>

                <Pressable
                  style={[
                    styles.boatButton,
                    selectedBoat === 0x02 && styles.boatButtonActive,
                  ]}
                  onPress={() => handleSetBoatType(0x02)}
                  disabled={boatBusy}
                >
                  <Text
                    style={[
                      styles.boatButtonText,
                      selectedBoat === 0x02 && styles.boatButtonTextActive,
                    ]}
                  >
                    {t("info2.boatRacing")}
                  </Text>
                </Pressable>
              </View>
            </View>

            {/* 3. 设备信息（内含固件升级按钮） */}
            <View style={styles.infoCard}>
              <View style={styles.infoHeader}>
                <Text style={styles.infoTitle}>{t("info.title")}</Text>
              </View>

              <View style={styles.infoRow}>
                <Text style={styles.infoLabel}>{t("info.bluetoothName")}</Text>
                <Text style={styles.infoValue}>{peripheral?.name || t("common.unknown")}</Text>
              </View>

              <View style={styles.infoRow}>
                <Text style={styles.infoLabel}>{t("info.idNumber")}</Text>
                <Text style={styles.infoValue}>{serial}</Text>
              </View>

              <View style={styles.infoRow}>
                <Text style={styles.infoLabel}>{t("info.firmwareVersion")}</Text>
                <View style={styles.firmwareRightWrap}>
                  <Text style={styles.infoValue}>{firmware}</Text>
                  <Pressable
                    style={[
                      styles.inlineDfuButton,
                      upgradeCheckDone &&
                        upgradeAvailable &&
                        styles.inlineDfuButtonHot,
                      (!isConnected || isLoading || boatBusy) &&
                        styles.inlineDfuButtonDisabled,
                    ]}
                    onPress={goToDfu}
                    disabled={!isConnected || isLoading || boatBusy}
                  >
                    <Text
                      style={[
                        styles.inlineDfuButtonText,
                        upgradeCheckDone &&
                          upgradeAvailable &&
                          styles.inlineDfuButtonTextHot,
                      ]}
                    >
                      {t("info.firmwareUpgrade")}
                    </Text>
                  </Pressable>
                </View>
              </View>

              <View style={styles.infoRow}>
                <Text style={styles.infoLabel}>{t("info.battery")}</Text>
                <Text style={styles.infoValue}>{battery}</Text>
              </View>

              <View style={styles.infoRow}>
                <Text style={styles.infoLabel}>{t("info2.latestFirmware")}</Text>
                <Text style={styles.infoValue}>
                  {upgradeCheckDone ? latestFirmware : t("info2.checking")}
                </Text>
              </View>

              <View style={[styles.infoRow, styles.infoRowLast]}>
                <Text style={styles.infoLabel}>{t("info.connectionStatus")}</Text>
                <Text
                  style={[
                    styles.infoValue,
                    isConnected ? styles.connectedText : styles.disconnectedText,
                  ]}
                >
                  {isConnected ? t("info.connected") : t("info.disconnected")}
                </Text>
              </View>
            </View>
          </>
        )}
      </ScrollView>
    </>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#f2f3f7",
  },
  contentContainer: {
    padding: 16,
    gap: 12,
    backgroundColor: "#f2f3f7",
  },

  cadenceCard: {
    backgroundColor: "#FFFFFF",
    borderRadius: 12,
    borderWidth: 1,
    borderColor: "#E7141E",
    paddingVertical: 58,
    paddingHorizontal: 20,
    alignItems: "center",
    marginBottom: 4,
  },
  cadenceLabel: {
    color: "#666666",
    fontSize: 20,
    marginBottom: 12,
    fontWeight: "500",
  },
  cadenceValue: {
    color: "#E7141E",
    fontSize: 100,
    fontWeight: "700",
    lineHeight: 108,
  },
  cadenceUnit: {
    color: "#666666",
    fontSize: 18,
    marginTop: 10,
  },

  sectionCard: {
    backgroundColor: "#FFFFFF",
    borderRadius: 12,
    borderWidth: 1,
    borderColor: "#E7141E",
    padding: 16,
    marginBottom: 4,
  },
  sectionHeader: {
    flexDirection: "row",
    justifyContent: "space-between",
    alignItems: "center",
    marginBottom: 16,
  },
  sectionTitle: {
    color: "#111111",
    fontSize: 16,
    fontWeight: "600",
  },
  statusContainer: {
    flexDirection: "row",
    alignItems: "center",
  },
  statusTextBusy: {
    color: "#FF9800",
    fontSize: 14,
    fontWeight: "500",
  },
  statusTextSuccess: {
    color: "#4CAF50",
    fontSize: 20,
    fontWeight: "bold",
  },
  statusTextError: {
    color: "#F44336",
    fontSize: 16,
    fontWeight: "bold",
  },
  statusText: {
    color: "#444444",
    fontSize: 14,
  },
  buttonRow: {
    flexDirection: "row",
    justifyContent: "space-between",
    gap: 10,
  },
  boatButton: {
    flex: 1,
    backgroundColor: "#FFFFFF",
    borderWidth: 1,
    borderColor: "#E7141E",
    borderRadius: 10,
    paddingVertical: 10,
    alignItems: "center",
  },
  boatButtonActive: {
    backgroundColor: "#E7141E",
  },
  boatButtonText: {
    color: "#E7141E",
    fontSize: 15,
    fontWeight: "600",
  },
  boatButtonTextActive: {
    color: "#FFFFFF",
  },

  infoCard: {
    backgroundColor: "#FFFFFF",
    borderRadius: 12,
    borderWidth: 1,
    borderColor: "#E7141E",
    paddingHorizontal: 14,
    paddingVertical: 4,
  },
  infoHeader: {
    paddingBottom: 4,
  },
  infoTitle: {
    color: "#111111",
    fontSize: 16,
    fontWeight: "600",
  },
  infoRow: {
    flexDirection: "row",
    justifyContent: "space-between",
    alignItems: "center",
    paddingVertical: 5,
    borderBottomWidth: 1,
    borderBottomColor: "#F0F0F0",
  },
  infoRowLast: {
    borderBottomWidth: 0,
  },
  infoLabel: {
    color: "#666666",
    fontSize: 13,
    flexShrink: 0,
    marginRight: 12,
  },
  infoValue: {
    color: "#111111",
    fontSize: 14,
    fontWeight: "600",
  },
  firmwareRightWrap: {
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "flex-end",
    flexShrink: 1,
  },
  inlineDfuButton: {
    marginLeft: 10,
    backgroundColor: "#D9D9D9",
    borderRadius: 8,
    paddingHorizontal: 10,
    paddingVertical: 5,
  },
  inlineDfuButtonHot: {
    backgroundColor: "#E7141E",
  },
  inlineDfuButtonDisabled: {
    opacity: 0.6,
  },
  inlineDfuButtonText: {
    color: "#333333",
    fontSize: 12,
    fontWeight: "600",
  },
  inlineDfuButtonTextHot: {
    color: "#FFFFFF",
  },
  connectedText: {
    color: "#0A9F4B",
  },
  disconnectedText: {
    color: "#D43C3C",
  },
});
