// @ts-nocheck
import { View, Image } from "@tarojs/components";
import Taro, { useRouter } from "@tarojs/taro";
import "./index.scss";
import { AtButton, AtDrawer, AtIcon } from "taro-ui";
import React, { useEffect, useState, useRef, useCallback } from "react";
import { chunks as infoChunks, headers as infoHeaders } from "./info.md";
import hackrobot from "../../images/hackrobot.jpg";

const PB_URL = "https://pocketbase.hackrobot.cn";
function getPb() {
  const PB = typeof window !== "undefined" && window.PocketBase;
  return PB ? new PB(PB_URL) : null;
}

const LazyChunk = React.memo(({ html, estimatedHeight, forceVisible }) => {
  const [visible, setVisible] = useState(forceVisible);
  const ref = useRef(null);
  const show = forceVisible || visible;

  useEffect(() => {
    if (forceVisible) return;
    if (visible) return;
    const el = ref.current;
    if (!el) return;
    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setVisible(true);
          observer.disconnect();
        }
      },
      { rootMargin: "1200px 0px" }
    );
    observer.observe(el);
    return () => observer.disconnect();
  }, [forceVisible, visible]);

  if (show) {
    return <div className="chunk-enter" dangerouslySetInnerHTML={{ __html: html }} />;
  }
  return <div ref={ref} className="chunk-placeholder" style={{ minHeight: estimatedHeight }} />;
});

const Book = () => {
  const [isWeChat, setisWeChat] = useState(false);
  const [show, setshow] = useState(false);
  const contentRef = useRef(null);
  const [paidType, setPaidType] = useState(null);
  const [userId, setUserId] = useState(Taro.getStorageSync("userId") || null);
  const [loading, setLoading] = useState(true);
  const [forceShowAll, setForceShowAll] = useState(false);
  const [readProgress, setReadProgress] = useState(0);
  const [showBackTop, setShowBackTop] = useState(false);
  const [bookData, setBookData] = useState(null);
  const router = useRouter();
  const [vipbook, setVipbook] = useState(false);

  useEffect(() => {
    setVipbook(router?.params?.type === "vipbook");
  }, []);

  const saveUserId = (id) => {
    Taro.setStorageSync("userId", id);
    setUserId(id);
  };

  const getLocalPaidType = () => Taro.getStorageSync("paidType") || null;

  const savePaidType = (type) => {
    Taro.setStorageSync("paidType", type);
    setPaidType(type);
  };

  const checkPaymentFromPB = async (uid) => {
    try {
      const pb = getPb();
      if (!pb) return getLocalPaidType();
      const records = await pb.collection("payments").getList(1, 1, {
        filter: `user_id = "${uid}"`,
        sort: "-created",
      });
      if (records.items.length > 0) {
        savePaidType(records.items[0].type);
        saveUserId(records.items[0].user_id);
        return records.items[0].type;
      }
      savePaidType(null);
      return null;
    } catch (err) {
      console.error("查询 PocketBase 失败:", err);
      return getLocalPaidType();
    }
  };

  const clearAllStorage = () => {
    try {
      Taro.clearStorageSync();
      if (typeof window !== "undefined" && window.localStorage) {
        window.localStorage.clear();
      }
      setPaidType(null);
      setLoading(false);
      Taro.showToast({ title: "本地存储已清空", icon: "success", duration: 2000 });
    } catch (error) {
      console.error("清空存储失败:", error);
      Taro.showToast({ title: "清空存储失败", icon: "none" });
    }
  };

  const isWeChatFun = () => {
    const ua = navigator.userAgent.toLowerCase();
    setisWeChat(ua.includes("micromessenger"));
  };

  const getOrCreateUserId = () => {
    let id = Taro.getStorageSync("userId");
    if (!id) {
      id = `user${Date.now()}`;
      Taro.setStorageSync("userId", id);
    }
    return id;
  };

  useEffect(() => {
    isWeChatFun();
    if (router?.params?.type === "clean") {
      clearAllStorage();
      return;
    }
    const init = async () => {
      const currentUserId = getOrCreateUserId();
      const localType = getLocalPaidType();
      const localUserId = Taro.getStorageSync("userId");
      if (localType && localUserId) {
        setPaidType(localType);
        setUserId(localUserId);
        setLoading(false);
        return;
      }
      await checkPaymentFromPB(currentUserId);
      setLoading(false);
    };
    init();
  }, []);

  const isPaid = paidType === "book" || vipbook;

  useEffect(() => {
    if (isPaid && !bookData) {
      import("./book.md").then(mod => {
        setBookData({ chunks: mod.chunks, headers: mod.headers });
      });
    }
  }, [isPaid, bookData]);

  const activeChunks = isPaid && bookData ? bookData.chunks : infoChunks;
  const activeHeaders = isPaid && bookData ? bookData.headers : infoHeaders;
  const contentLoading = loading || (isPaid && !bookData);

  useEffect(() => {
    let ticking = false;
    const onScroll = () => {
      if (ticking) return;
      ticking = true;
      requestAnimationFrame(() => {
        const scrollTop = window.scrollY || document.documentElement.scrollTop;
        const docHeight = document.documentElement.scrollHeight - window.innerHeight;
        setReadProgress(docHeight > 0 ? Math.min(100, (scrollTop / docHeight) * 100) : 0);
        setShowBackTop(scrollTop > 600);
        ticking = false;
      });
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  useEffect(() => {
    const el = contentRef.current;
    if (!el || contentLoading) return;
    const onImgLoad = (e) => {
      if (e.target.tagName === "IMG") e.target.classList.add("loaded");
    };
    el.addEventListener("load", onImgLoad, true);
    const checkCached = () => {
      el.querySelectorAll("img").forEach(img => {
        if (img.complete) img.classList.add("loaded");
      });
    };
    const mo = new MutationObserver(checkCached);
    mo.observe(el, { childList: true, subtree: true });
    checkCached();
    return () => {
      el.removeEventListener("load", onImgLoad, true);
      mo.disconnect();
    };
  }, [contentLoading]);

  const handleJump = useCallback((index) => {
    setForceShowAll(true);
    setshow(false);

    const run = () => {
      const root = contentRef.current;
      if (!root) return;
      const h1s = root.querySelectorAll("h1");
      const el = h1s[index];
      if (el) {
        try {
          el.scrollIntoView({ behavior: "smooth", block: "start" });
        } catch (_) {
          const top = el.getBoundingClientRect().top + (window.pageYOffset || document.documentElement.scrollTop) - 60;
          window.scrollTo({ top: Math.max(0, top), behavior: "smooth" });
        }
      }
    };

    run();
    setTimeout(run, 100);
    setTimeout(run, 300);
    setTimeout(run, 600);
  }, []);

  const submitPayForm = (xorpayUrl, xorpayParams) => {
    const form = document.createElement("form");
    form.method = "POST";
    form.action = xorpayUrl;
    form.style.display = "none";
    for (const key in xorpayParams) {
      const input = document.createElement("input");
      input.type = "hidden";
      input.name = key;
      input.value = xorpayParams[key];
      form.appendChild(input);
    }
    document.body.appendChild(form);
    form.submit();
    setTimeout(() => document.body.removeChild(form), 1000);
  };

  // 参考 nomadvip 解锁 VIP：微信内必须 xorpay，PC/手机浏览器 zpay
  const getDeviceAndProvider = () => {
    const ua = typeof navigator !== "undefined" ? navigator.userAgent.toLowerCase() : "";
    const inWeChat = ua.includes("micromessenger");
    if (inWeChat) return { device: "wechat", provider: "xorpay" };
    const isMobile = /mobile|android|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(ua);
    return { device: isMobile ? "h5" : "pc", provider: "zpay" };
  };

  const payh5 = (type, total_fee = 1000) => {
    const uid = getOrCreateUserId();
    const returnUrl = typeof window !== "undefined" ? `${window.location.origin}${window.location.pathname || "/book"}` : "";
    const { device, provider } = getDeviceAndProvider();
    Taro.request({
      method: "POST",
      url: `${process.env.TARO_API_API}/payh5`,
      data: {
        user_id: uid,
        return_url: returnUrl,
        total_fee,
        type,
        channel: "wxpay",
        device,
        provider,
      },
      header: { "content-type": "application/json" },
      success: (res) => {
        const data = res.data || {};
        const params = data.xorpay_params ?? data.params ?? {};
        const payUrl = data.xorpay_url ?? data.pay_url ?? "";
        if (params && Object.keys(params).length > 0 && payUrl) {
          submitPayForm(payUrl, params);
        } else {
          Taro.showToast({ title: data?.detail || data?.msg || "支付发起失败", icon: "none" });
        }
      },
      fail: () => Taro.showToast({ title: "网络错误", icon: "none" }),
    });
  };

  return (
    <>
      <View className="reading-progress" style={{ width: `${readProgress}%` }} />

      <View className="book_header_div" />
      <View className="book_header">
        <View className="book_header_left" onClick={() => Taro.redirectTo({ url: "/" })}>
          <AtIcon value="chevron-left" />
        </View>
        <View className="book_header_middle">数字游民</View>
        <View className={`book_header_right ${show ? "active" : ""}`} onClick={() => setshow(!show)}>
          <AtIcon value="bullet-list" />
          <View className="book_header_right_text pc-only">目录</View>
        </View>
      </View>

      <View className="Book">
        {contentLoading ? (
          <View className="markdown-loading">
            <View className="loading-spinner" />
            <View className="loading-text">正在加载...</View>
          </View>
        ) : (
          <View ref={contentRef} className="markdown-body">
            {activeChunks.map((chunk, i) => (
              <LazyChunk
                key={`${isPaid}-${i}`}
                html={chunk.html}
                estimatedHeight={chunk.estimatedHeight}
                forceVisible={forceShowAll || i === 0}
              />
            ))}
          </View>
        )}

        <AtDrawer
          className="book_AtDrawer"
          show={show}
          mask
          items={activeHeaders}
          onItemClick={(index) => handleJump(index)}
          onClose={() => setshow(false)}
        />

        {!isWeChat && (
          <View className="qrcode-section">
            <Image
              className="hackrobot"
              src={hackrobot}
              style={{ width: "300px", height: "300px" }}
              lazyLoad
            />
          </View>
        )}

        {!isPaid && (
          <AtButton
            type="primary"
            size="normal"
            className="joinSalon"
            onClick={() => payh5("book", 4900)}
          >
            阅读更多
          </AtButton>
        )}
      </View>

      {showBackTop && (
        <View
          className="back-to-top"
          onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })}
        >
          <AtIcon value="chevron-up" size="20" />
        </View>
      )}
    </>
  );
};

export default Book;
