import React, { useEffect, useRef, useState } from "react";
import { View, Text, StyleSheet, Alert, Platform } from "react-native";
import { NativeStackScreenProps } from "@react-navigation/native-stack";
import { RootStackParamList } from "../App";
import RNFS from "react-native-fs";
import {
  startDfu,
  addDfuEventListener,
  DfuProgressEvent,
  DfuStateEvent,
} from "@systemic-games/react-native-nordic-nrf5-dfu";
import { useTranslation } from "react-i18next";
import MyStatusbar from "./component/MyStatusbar";
import MyHeader from "./component/MyHeader";

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

interface DeviceInfo {
  hardware: number;
  latestFirmware: string;
  download: string;
}

interface ParsedFirmware {
  hardware: number;
  iteration: number;
  build: string;
  raw: string;
}

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,
  };
};

const trace = (step: string, payload?: unknown) => {
  const timestamp = new Date().toISOString();
  if (payload === undefined) {
    console.log(`[DFU-TRACE ${timestamp}] ${step}`);
  } else {
    console.log(`[DFU-TRACE ${timestamp}] ${step}`, payload);
  }
};

export default function DfuScreen({ route, navigation }: Props) {
  const {
    deviceId,
    name,
    firmware: deviceFirmware,
  } = route.params;
  const { t } = useTranslation();

  const [progress, setProgress] = useState(0);
  const [state, setState] = useState(t("dfu.preparing"));
  const [error, setError] = useState<string>();
  const [latestVersion, setLatestVersion] = useState(t("dfu.reading"));
  const [isDfuRunning, setIsDfuRunning] = useState(false);
  const startedRef = useRef(false);

  const mapDfuStateToLabel = (s: string): string => {
    switch (s) {
      case "connecting":
        return t("dfu.stateConnecting");
      case "starting":
        return t("dfu.stateStarting");
      case "enablingDfuMode":
        return t("dfu.stateEnablingDfuMode");
      case "uploading":
        return t("dfu.stateUploading");
      case "validating":
        return t("dfu.stateValidating");
      case "disconnecting":
        return t("dfu.stateDisconnecting");
      case "completed":
        return t("dfu.stateCompleted");
      case "aborted":
        return t("dfu.stateAborted");
      case "failed":
      case "dfu_failed":
        return t("dfu.stateFailed");
      case "initializing":
        return t("dfu.stateInitializing");
      case "errored":
        return t("dfu.stateErrored");
      default:
        return s;
    }
  };

  useEffect(() => {
    const unsubscribe = navigation.addListener("beforeRemove", (e) => {
      if (!isDfuRunning) return;
      e.preventDefault();
      Alert.alert(t("dfu.pleaseWait"), t("dfu.doNotReturn"));
    });

    return unsubscribe;
  }, [navigation, isDfuRunning, t]);

  useEffect(() => {
    trace("screen mounted", {
      routeParams: {
        deviceId,
        name,
        deviceFirmware,
      },
    });

    return () => {
      trace("screen unmounted");
    };
  }, [deviceId, name, deviceFirmware]);

  useEffect(() => {
    const sub = addDfuEventListener("log", (ev) => {
      trace("dfu native log", ev);
    });

    return () => {
      sub.remove();
    };
  }, []);

  useEffect(() => {
    if (startedRef.current) {
      trace("runDfu duplicate effect skipped");
      return;
    }
    startedRef.current = true;

    const runDfu = async () => {
      try {
        trace("runDfu begin");
        setIsDfuRunning(true);
        setError(undefined);

        const rawDeviceId = String(deviceId ?? "").trim();
        const safeDeviceId = rawDeviceId;

        const firmwareText = String(deviceFirmware ?? "").trim();

        trace("resolved input", {
          rawDeviceId,
          safeDeviceId,
          firmwareText,
        });

        if (!safeDeviceId) {
          throw new Error(t("dfu.invalidTargetDeviceId"));
        }

        const currentFw = parseFirmwareVersion(firmwareText);
        trace("parsed current firmware", currentFw);

        const manifestUrl =
          "https://powerfun.oss-cn-shanghai.aliyuncs.com/yecongdfu/latest.json";
        const manifestPath = RNFS.CachesDirectoryPath + "/latest.json";

        trace("manifest fetch start", { manifestUrl, manifestPath });
        const manifestResp = await fetch(manifestUrl);
        trace("manifest fetch response", { status: manifestResp.status });

        if (!manifestResp.ok) {
          throw new Error(
            t("dfu.manifestDownloadFailed", { status: manifestResp.status })
          );
        }

        const manifestText = await manifestResp.text();
        trace("manifest text loaded", { length: manifestText.length });

        await RNFS.writeFile(manifestPath, manifestText, "utf8");
        trace("manifest saved", { manifestPath });

        let manifest: { devices: DeviceInfo[] };

        try {
          manifest = JSON.parse(manifestText) as { devices: DeviceInfo[] };
        } catch (e) {
          throw new Error(
            t("dfu.manifestInvalidJson", {
              preview: manifestText.slice(0, 200),
            })
          );
        }

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

        trace("manifest device matched", { deviceInfo });

        if (!deviceInfo) {
          setIsDfuRunning(false);
          Alert.alert(
            t("dfu.cannotUpgrade"),
            t("dfu.hardwareNotFound", { hardware: currentFw.hardware }),
            [{ text: t("dfu.confirm"), onPress: () => navigation.goBack() }]
          );
          return;
        }

        setLatestVersion(deviceInfo.latestFirmware);

        const latestFw = parseFirmwareVersion(deviceInfo.latestFirmware);
        trace("parsed latest firmware", latestFw);

        if (latestFw.hardware !== currentFw.hardware) {
          throw new Error(
            t("dfu.hardwareMismatch", {
              current: currentFw.hardware,
              latest: latestFw.hardware,
            })
          );
        }

        if (latestFw.iteration <= currentFw.iteration) {
          setIsDfuRunning(false);
          Alert.alert(t("dfu.noNeedUpgrade"), t("dfu.alreadyLatest"), [
            { text: t("dfu.confirm"), onPress: () => navigation.goBack() },
          ]);
          return;
        }

        trace("upgrade allowed", {
          currentIteration: currentFw.iteration,
          latestIteration: latestFw.iteration,
        });

        const localPath = RNFS.CachesDirectoryPath + "/firmware.zip";

        const oldFileExists = await RNFS.exists(localPath);
        if (oldFileExists) {
          await RNFS.unlink(localPath);
          trace("removed stale firmware zip", { localPath });
        }

        trace("firmware download start", {
          downloadUrl: deviceInfo.download,
          localPath,
        });

        const downloadResult = await RNFS.downloadFile({
          fromUrl: deviceInfo.download,
          toFile: localPath,
          background: false,
          discretionary: false,
        }).promise;

        trace("firmware download result", downloadResult);

        if (downloadResult.statusCode !== 200) {
          throw new Error(
            t("dfu.firmwareDownloadFailed", {
              status: downloadResult.statusCode,
            })
          );
        }

        const fileExists = await RNFS.exists(localPath);
        trace("firmware exists check", { fileExists });

        if (!fileExists) {
          throw new Error(t("dfu.firmwareFileMissing", { path: localPath }));
        }

        const fileStat = await RNFS.stat(localPath);
        const fileSize = Number(fileStat.size ?? 0);
        trace("firmware stat", fileStat);

        if (!Number.isFinite(fileSize) || fileSize <= 0) {
          throw new Error(
            t("dfu.firmwareFileInvalid", { size: String(fileStat.size) })
          );
        }

        const dfuFilePath = "file://" + localPath;
        let iosBootloaderName: string | undefined;
        if (Platform.OS === "ios") {
          if (name?.startsWith("PF-PM5-")) {
            iosBootloaderName = "PF-PM5-DFU";
          } else if (name?.startsWith("PF-STK-")) {
            iosBootloaderName = "PF-STK-DFU";
          }
        }

        trace("startDfu call", {
          safeDeviceId,
          dfuFilePath,
          localPath,
          fileSize,
          currentFirmware: currentFw.raw,
          latestFirmware: latestFw.raw,
          iosBootloaderName,
        });

        await startDfu(safeDeviceId, dfuFilePath, {
          alternativeAdvertisingName: iosBootloaderName,
          dfuStateListener: (ev: DfuStateEvent) => {
            trace("dfu state", ev);
            setState(ev.state);
          },
          dfuProgressListener: (ev: DfuProgressEvent) => {
            trace("dfu progress", ev);
            setProgress(ev.percent);
          },
        });

        trace("startDfu resolved successfully");
        setIsDfuRunning(false);
        Alert.alert(t("dfu.upgradeSuccess"), t("dfu.upgradeSuccessMessage"), [
  {
    text: t("dfu.confirm"),
    onPress: () => {
      navigation.reset({
        index: 0,
        routes: [{ name: "Home" }],
      });
    },
  },
]);
      } catch (err: any) {
        trace("runDfu error", {
          message: err?.message,
          code: err?.code,
          name: err?.name,
          error: err,
        });
        setIsDfuRunning(false);
        setError(err?.message || t("dfu.dfuFailed"));
        Alert.alert(t("dfu.upgradeFailed"), err?.message || t("dfu.dfuFailed"), [
          { text: t("dfu.confirm"), onPress: () => navigation.goBack() },
        ]);
      }
    };

    runDfu();
  }, [deviceId, name, deviceFirmware, navigation, t]);

  return (
    <View style={styles.container}>
      <MyStatusbar backgroundColor="#FFFFFF" dark />
      <MyHeader
        title={t("dfu.title")}
        textColor="#333"
        backgroundColor="#FFFFFF"
        navigation={navigation}
      />

      <View style={styles.content}>
        <View style={styles.row}>
          <Text style={styles.titleText}>
            {t("dfu.bluetoothName")}: {name || "--"}
          </Text>
        </View>

        <View style={styles.row}>
          <Text style={styles.normalText}>
            {t("dfu.latestVersion")}: {latestVersion}
          </Text>
        </View>

        <View style={styles.row}>
          <Text style={styles.normalText}>
            {t("dfu.currentVersion")}: {deviceFirmware || "--"}
          </Text>
        </View>

        <View style={styles.row}>
          <Text style={styles.normalText}>
            {t("dfu.upgradeStatus")}: {mapDfuStateToLabel(state)}
          </Text>
        </View>

        <View style={styles.progressContainer}>
          <View style={[styles.progressBar, { width: `${progress}%` }]} />
          <Text style={styles.progressText}>{progress}%</Text>
        </View>

        {!!error && <Text style={styles.errorText}>{error}</Text>}
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#FFFFFF",
  },
  content: {
    flex: 1,
    padding: 20,
    backgroundColor: "#FFFFFF",
  },
  row: {
    borderBottomWidth: 1,
    borderBottomColor: "#E7141E",
    paddingBottom: 6,
    marginBottom: 12,
  },
  titleText: {
    fontSize: 18,
    color: "#111111",
    fontWeight: "600",
  },
  normalText: {
    fontSize: 16,
    color: "#222222",
  },
  progressContainer: {
    height: 30,
    backgroundColor: "#EEEEEE",
    borderRadius: 15,
    overflow: "hidden",
    marginTop: 40,
    justifyContent: "center",
  },
  progressBar: {
    height: "100%",
    backgroundColor: "#E7141E",
  },
  progressText: {
    position: "absolute",
    alignSelf: "center",
    fontWeight: "bold",
    color: "#000000",
  },
  errorText: {
    color: "red",
    marginTop: 20,
    fontSize: 14,
  },
});
