import "dotenv/config";
import _ from "lodash";
import pLimit from "p-limit";
import { io } from "socket.io-client";
import {
  createApiBid,
  createBidProduct,
  deleteProfile,
  shouldUpdateProductTab,
} from "./service/app-service.js";
import { updateLoginStatus } from "./system/apis/bid.js";
import browser from "./system/browser.js";
import configs from "./system/config.js";
import {
  delay,
  extractModelId,
  isTimeReached,
  randomDelayWithMeta,
  safeClosePage,
  subtractSeconds,
} from "./system/utils.js";
import CONSTANTS from "./system/constants.js";

global.IS_CLEANING = true;

let MANAGER_BIDS = [];

const activeTasks = new Set();

let timeToUpdateLogin = new Date().toUTCString();

const handleUpdateProductTabs = (data) => {
  if (!Array.isArray(data)) {
    console.log("Data must be array");
    return;
  }

  const managerBidMap = new Map(MANAGER_BIDS.map((bid) => [bid.id, bid]));

  const newDataManager = data.map(({ children, ...web }) => {
    const prevApiBid = managerBidMap.get(web.id);

    const newChildren = children.map((item) => {
      const prevProductTab = prevApiBid?.children.find((i) => i.id === item.id);

      if (prevProductTab) {
        prevProductTab.setNewData(item);

        return prevProductTab;
      }

      return createBidProduct(web, item);
    });

    if (prevApiBid) {
      prevApiBid.setNewData({ children: newChildren, ...web });
      return prevApiBid;
    }

    return createApiBid({ ...web, children: newChildren });
  });

  MANAGER_BIDS = newDataManager;
};

const addProductTab = (data) => {
  if (
    typeof data !== "object" ||
    data === null ||
    !Array.isArray(data.children)
  ) {
    console.warn("Data must be an object with a children array");
    return;
  }

  const { children, ...web } = data;

  if (children.length === 0) {
    console.warn(
      `⚠️ No children found for bid id ${web.id}, skipping addProductTab`
    );
    return;
  }

  const managerBidMap = new Map(MANAGER_BIDS.map((bid) => [bid.id, bid]));
  const prevApiBid = managerBidMap.get(web.id);

  if (prevApiBid) {
    // Cập nhật
    const updatedChildren = prevApiBid.children;

    children.forEach((newChild) => {
      const existingChildIndex = updatedChildren.findIndex(
        (c) => c.id === newChild.id
      );

      if (existingChildIndex !== -1) {
        updatedChildren[existingChildIndex].setNewData(newChild);
      } else {
        updatedChildren.push(createBidProduct(web, newChild));
      }
    });

    prevApiBid.setNewData({ ...web, children: updatedChildren });
  } else {
    // Tạo mới
    const newChildren = children.map((item) => createBidProduct(web, item));
    const newApiBid = createApiBid({ ...web, children: newChildren });

    MANAGER_BIDS.push(newApiBid);

    console.log("%cindex.js:116 {MANAGER_BIDS}", "color: #007acc;", {
      MANAGER_BIDS,
      children: newChildren,
    });
  }
};

const tracking = async () => {
  console.log("🚀 Tracking process started...");

  while (true) {
    try {
      console.log("🔍 Scanning active bids...");
      const productTabs = _.flatMap(MANAGER_BIDS, "children");

      await Promise.allSettled(
        MANAGER_BIDS.filter((bid) => !bid.page_context).map((apiBid) => {
          console.log(`🎧 Listening to events for API Bid ID: ${apiBid.id}`);
          return apiBid.listen_events();
        })
      );

      await Promise.allSettled(
        MANAGER_BIDS.filter((bid) => !bid.page_context).map((apiBid) => {
          console.log(`🎧 Listening to events for close login: ${apiBid.id}`);
          return (apiBid.onCloseLogin = (data) => {
            // Loại bỏ class hiện có. Tạo tiền đề cho việc tạo đối tượng mới lại
            MANAGER_BIDS = MANAGER_BIDS.filter(
              (item) => item.id !== data.id && item.type !== data.type
            );

            addProductTab(data);
          });
        })
      );

      Promise.allSettled(
        productTabs.map(async (productTab) => {
          console.log(`📌 Processing Product ID: ${productTab.id}`);
          console.log(
            `🔍 [${
              productTab.id
            }] Current URL: ${await productTab.page_context?.url?.()}`
          );

          // Xác định parent context
          if (!productTab.parent_browser_context) {
            const parent = _.find(MANAGER_BIDS, { id: productTab.web_bid.id });
            productTab.parent_browser_context = parent?.browser_context;
            if (!productTab.parent_browser_context) {
              console.log(
                `⏳ Waiting for parent process... (Product ID: ${productTab.id})`
              );
              return;
            }
          }

          // Thời điểm tracking liên tục
          const earlyTrackingTime = subtractSeconds(
            productTab.close_time,
            productTab.getEarlyTrackingSeconds() || 0
          );

          // Check không mở tab nếu chưa đến giờ
          if (productTab.close_time && !isTimeReached(earlyTrackingTime)) {
            console.log(
              `⏳ [${productTab.id}] Early tracking time not reached yet. ` +
                `Waiting until ${earlyTrackingTime} (current time: ${new Date().toISOString()})`
            );
            return;
          }

          // Kết nối Puppeteer nếu chưa có page_context
          if (!productTab.page_context) {
            console.log(
              `🔌 Connecting to page for Product ID: ${productTab.id}`
            );
            await productTab.puppeteer_connect();
          }

          // Kiểm tra URL và điều hướng nếu cần
          if ((await productTab.page_context.url()) !== productTab.url) {
            if (global[`IS_PLACE_BID-${productTab.id}`]) return;

            console.log(
              `🔄 Redirecting to new URL for Product ID: ${productTab.id}`
            );
            await productTab.gotoLink();
          }

          // Cập nhật nếu cần thiết
          if (shouldUpdateProductTab(productTab)) {
            console.log(`🔄 Updating Product ID: ${productTab.id}...`);
            await productTab.update();
          } else {
            console.log(
              `⏳ Product ID: ${productTab.id} was updated recently. Skipping update.`
            );
          }

          // Chờ first bid
          if (!productTab.first_bid) {
            console.log(
              `🎯 Waiting for first bid for Product ID: ${productTab.id}`
            );
            return;
          }

          // Kiểm tra thời gian bid
          if (
            productTab.start_bid_time &&
            !isTimeReached(productTab.start_bid_time)
          ) {
            console.log(
              `⏳ Not yet time to bid. Skipping Product ID: ${productTab.id}`
            );
            return;
          }

          await productTab.action();
        })
      );

      // Dọn dẹp tab không dùng
      console.log("🧹 Cleaning up unused tabs...");
      clearLazyTab();

      // Cập nhật trạng thái tracking
      console.log("📊 Tracking work status...");
      workTracking();

      // Bắn event status login
      console.log("📊 Tracking login status...");
      trackingLoginStatus();
    } catch (error) {
      console.error("❌ Error in tracking loop:", error);
    }

    console.log(
      `⏳ Waiting ${
        configs.AUTO_TRACKING_DELAY / 1000
      } seconds before the next iteration...`
    );
    await delay(configs.AUTO_TRACKING_DELAY);
  }
};

const clearLazyTab = async () => {
  if (!global.IS_CLEANING) {
    console.log("🚀 Cleaning flag is OFF. Proceeding with operation.");
    return;
  }

  if (!browser) {
    console.warn("⚠️ Browser is not available or disconnected.");
    return;
  }

  try {
    const pages = await browser.pages();
    console.log("🔍 Found pages:", pages.length);

    const activeUrls = _.flatMap(MANAGER_BIDS, (item) => [
      item.url,
      ...item.children.map((child) => child.url),
    ]).filter(Boolean);

    // product tabs
    const productTabs = _.flatMap(MANAGER_BIDS, "children");

    for (const page of pages) {
      try {
        if (page.isClosed()) continue; // Trang đã đóng thì bỏ qua

        const pageUrl = page.url();

        if (!pageUrl || pageUrl === "about:blank") continue;

        if (activeUrls.includes(pageUrl)) {
          const productTab = productTabs.find((item) => item.url === pageUrl);

          if (!productTab || !productTab?.close_time) continue;

          const earlyTrackingTime = subtractSeconds(
            productTab.close_time,
            productTab.getEarlyTrackingSeconds() || 0
          );

          if (!isTimeReached(earlyTrackingTime)) {
            await safeClosePage(productTab);
            console.log(`🛑 Unused page detectedd: ${pageUrl}`);

            continue;
          }

          continue;
        }

        const modelProductTab = extractModelId(pageUrl);

        if (modelProductTab) {
          const productWatingUpdate = productTabs.find(
            (item) =>
              item.model === modelProductTab &&
              isTimeReached(item.close_time) &&
              item.status === "biding"
          );

          if (productWatingUpdate) {
            console.log("Waiting product update to close");
            continue;
          }
        }

        // remove all listents
        page.removeAllListeners();

        console.log(`🛑 Unused page detected: ${pageUrl}`);

        if (CONSTANTS.KEEP_LIVE_URLS.some((item) => pageUrl.includes(item))) {
          console.log("Url include keep live urls: " + pageUrl);
          continue;
        }

        const bidData = MANAGER_BIDS.filter((item) => item.page_context)
          .map((i) => ({
            current_url: i.page_context.url(),
            data: i,
          }))
          .find((j) => j.current_url === pageUrl);

        if (bidData && bidData.data) {
          await safeClosePage(bidData.data);
        } else {
          try {
            await Promise.race([
              page.close(),
              new Promise((_, reject) =>
                setTimeout(() => reject(new Error("Close timeout")), 3000)
              ),
            ]);
          } catch (closeErr) {
            console.warn(
              `⚠️ Error closing page ${pageUrl}: ${closeErr.message}`
            );
          }
        }

        console.log(`✅ Closed page: ${pageUrl}`);
      } catch (pageErr) {
        console.warn(`⚠️ Error handling page: ${pageErr.message}`);
      }
    }

    // Delete lazy tracking page
    Promise.allSettled(
      MANAGER_BIDS.map(async (item) => {
        if (await item.isLazy()) {
          safeClosePage(item);
        }
      })
    );
  } catch (err) {
    console.error("❌ Error in clearLazyTab:", err.message);
  }
};

const workTracking = async () => {
  try {
    const activeData = _.flatMap(MANAGER_BIDS, (item) => [
      item,
      ...item.children,
    ]);
    const limit = pLimit(5);

    await Promise.allSettled(
      activeData
        .filter((item) => item.page_context && !item.page_context.isClosed())
        .filter((item) => !activeTasks.has(item.id))
        .map((item) =>
          limit(async () => {
            activeTasks.add(item.id);
            try {
              await item.handleTakeWorkSnapshot();
            } catch (error) {
              console.error(
                `[❌ ERROR] Snapshot failed for Product ID: ${item.id}`,
                error
              );
            } finally {
              activeTasks.delete(item.id);
            }
          })
        )
    );
  } catch (error) {
    console.error(
      `[❌ ERROR] Work tracking failed: ${error.message}\n`,
      error.stack
    );
  }
};

const trackingLoginStatus = async () => {
  try {
    if (!MANAGER_BIDS?.length) return;

    const results = await Promise.allSettled(
      MANAGER_BIDS.map(async (item) => {
        try {
          if (!isTimeReached(timeToUpdateLogin)) return;

          const login_status = await item.isLogin();

          await updateLoginStatus({
            data: {
              id: item.id,
              type: item.type,
              origin_url: item.origin_url,
            },
            login_status,
          });

          // Set time to update login sau 1 phút
          const now = new Date();
          const oneMinuteLater = new Date(now.getTime() + 60 * 1000);

          timeToUpdateLogin = oneMinuteLater;
        } catch (err) {
          console.warn(
            `[⚠️ WARN] Failed to check login for bid ${
              item?.id || "unknown"
            }: ${err.message}`
          );
        }
      })
    );

    // Optional: log summary
    const failed = results.filter((r) => r.status === "rejected").length;
    if (failed) {
      console.warn(`[⚠️ WARN] ${failed} login status checks failed.`);
    }
  } catch (error) {
    console.error(
      `[❌ ERROR] Login status tracking failed: ${error.message}\n`,
      error.stack
    );
  }
};

(async () => {
  const socket = io(`${configs.SOCKET_URL}/bid-ws`, {
    transports: ["websocket"],
    reconnection: true,
    extraHeaders: {
      Authorization: process.env.CLIENT_KEY,
    },
  });

  // set socket on global app
  global.socket = socket;

  // listen connect
  socket.on("connect", () => {
    console.log("✅ Connected to WebSocket server");
    console.log("🔗 Socket ID:", socket.id);
  });

  // listen connect
  socket.on("disconnect", () => {
    console.log("❌Client key is valid. Disconnected");
  });

  // listen event
  socket.on("bidsUpdated", async (data) => {
    console.log("📢 Bids Data:", data);

    handleUpdateProductTabs(data);
  });

  socket.on("webUpdated", async (data) => {
    console.log("📢 Account was updated:", data);

    const webBid = MANAGER_BIDS.find((item) => item?.id === data?.id);

    if (
      webBid &&
      webBid.username === data.username &&
      webBid.password === data.password
    )
      return;

    const isDeleted = deleteProfile(data);

    if (isDeleted) {
      console.log("✅ Profile deleted successfully!");

      const tab = MANAGER_BIDS.find((item) => item.url === data.url);

      if (!tab) return;

      global.IS_CLEANING = false;
      await Promise.all(tab.children.map((tab) => safeClosePage(tab)));

      await safeClosePage(tab);

      MANAGER_BIDS = MANAGER_BIDS.filter((item) => item.id != data.id);

      addProductTab(data);

      global.IS_CLEANING = true;
    } else {
      console.log("⚠️ No profile found to delete.");
    }
  });

  // AUTO TRACKING
  tracking();
})();
