import * as fs from "fs";
import path from "path";
import BID_TYPE from "../system/bid-type.js";
import browser from "../system/browser.js";
import CONSTANTS from "../system/constants.js";
import {
  findEarlyLoginTime,
  findNearestClosingChild,
  getPathLocalData,
  getPathProfile,
  isTimeReached,
  sanitizeFileName,
  subtractSeconds,
} from "../system/utils.js";
import { Bid } from "./bid.js";

export class ApiBid extends Bid {
  id;
  account;
  children = [];
  children_processing = [];
  created_at;
  updated_at;
  origin_url;
  active;
  // browser_context;
  username;
  password;
  early_tracking_seconds;
  snapshot_at;

  constructor({
    url,
    username,
    password,
    id,
    children,
    created_at,
    updated_at,
    origin_url,
    active,
    early_tracking_seconds,
    snapshot_at,
  }) {
    super(BID_TYPE.API_BID, url);

    this.created_at = created_at;
    this.updated_at = updated_at;
    this.children = children;
    this.origin_url = origin_url;
    this.active = active;
    this.username = username;
    this.password = password;
    this.early_tracking_seconds = early_tracking_seconds;
    this.snapshot_at = snapshot_at;
    this.id = id;
  }

  setNewData({
    url,
    username,
    password,
    id,
    children,
    created_at,
    updated_at,
    origin_url,
    active,
    early_tracking_seconds,
    snapshot_at,
  }) {
    this.created_at = created_at;
    this.updated_at = updated_at;
    this.children = children;
    this.origin_url = origin_url;
    this.active = active;
    this.username = username;
    this.password = password;
    this.url = url;
    this.early_tracking_seconds = early_tracking_seconds;
    this.snapshot_at = snapshot_at;
  }

  puppeteer_connect = async () => {
    this.browser_context = await browser.createBrowserContext();

    const page = await this.browser_context.newPage();

    this.page_context = page;

    await this.restoreContext();
  };

  async handlePrevListen() {
    console.log(`👂 [${this.id}] Start handlePrevListen...`);

    // Chỉ bắt đầu check khi ảnh đã được chụp
    if (this.snapshot_at) {
      const nearestCloseTime = findNearestClosingChild(this);

      // Nếu không có roi vào 2 trường hợp
      // 1 là không có item nào đang hợp lệ
      // 2 là có item chưa được craw dữ liệu

      // Xử lí trường hợp 2
      if (!nearestCloseTime || this.children.some((item) => !item.close_time)) {
        console.log(`🔌 [${this.id}] Connecting to puppeteer...`);
        await this.puppeteer_connect();

        console.log(`✅ [${this.id}] Connected. Executing actions...`);
        await this.action();

        console.log(`🎯 [${this.id}] handlePrevListen completed.`);
        return true;
      }

      // Xử lí trường hợp có item hợp lệ ( close time gần với thời gian hiện tại)
      const { close_time } = nearestCloseTime;
      console.log(`📅 [${this.id}] Nearest close_time: ${close_time}`);

      const timeToTracking = subtractSeconds(
        close_time,
        nearestCloseTime.getEarlyTrackingSeconds() || 0
      );
      // const timeToTracking = subtractSeconds(
      //   close_time,
      //   this.early_tracking_seconds || 0
      // );

      console.log(
        `🕰️ [${this.id}] Time to tracking: ${new Date(
          timeToTracking
        ).toISOString()}`
      );

      if (!isTimeReached(timeToTracking)) {
        console.log(`⏳ [${this.id}] Not time to track yet.`);
        return false;
      }
    }

    console.log(`🔌 [${this.id}] Connecting to puppeteer...`);
    await this.puppeteer_connect();

    console.log(`✅ [${this.id}] Connected. Executing actions...`);
    await this.action();

    console.log(`🎯 [${this.id}] handlePrevListen completed.`);
    return true;
  }

  async isLazy() {
    // Nếu chưa có ảnh chụp working => tab not lazy
    if (!this.snapshot_at) return false;

    // Nếu có một children chưa có thông tin => tab not lazy
    if (this.children.some((item) => !item.close_time)) return false;

    const nearestCloseTime = findNearestClosingChild(this);

    // Nếu không có nearest close => tab not lazy
    if (!nearestCloseTime) return false;

    const { close_time } = nearestCloseTime;

    const timeToTracking = subtractSeconds(
      close_time,
      nearestCloseTime.getEarlyTrackingSeconds() || 0
    );

    // Nếu chưa đến giờ tracking => tab lazy
    if (!isTimeReached(timeToTracking)) return true;

    // Các trường hợp còn lại => not lazy
    return false;
  }

  listen_events = async () => {
    if (this.page_context) return;

    // await this.puppeteer_connect();

    // await this.action();

    const results = await this.handlePrevListen();

    if (!results) return;

    await this.saveContext();
  };

  async saveContext() {
    if (!this.browser_context || !this.page_context) return;

    try {
      const cookies = await this.browser_context.cookies();
      const localStorageData = await this.page_context.evaluate(() =>
        JSON.stringify(localStorage)
      );

      const contextData = {
        cookies,
        localStorage: localStorageData,
      };

      const dirPath = path.join(CONSTANTS.PROFILE_PATH);

      if (!fs.existsSync(dirPath)) {
        fs.mkdirSync(dirPath, { recursive: true });
        console.log(`📂 [${this.id}] Save at folder: ${dirPath}`);
      }

      fs.writeFileSync(
        path.join(dirPath, sanitizeFileName(this.origin_url) + ".json"),
        JSON.stringify(contextData, null, 2)
      );
      console.log(`✅ [${this.id}] Context saved!`);
    } catch (error) {
      console.log(`[${this.id}] Save Context: , ${error.message}`);
    }
  }

  async restoreContext() {
    if (!this.browser_context || !this.page_context) return;

    const filePath = getPathProfile(this.origin_url);

    if (!fs.existsSync(filePath)) return;

    const contextData = JSON.parse(fs.readFileSync(filePath, "utf8"));

    // Restore Cookies
    await this.page_context.setCookie(...contextData.cookies);

    console.log(`🔄 [${this.id}] Context restored!`);
  }

  async onCloseLogin() {}

  async isTimeToLogin() {
    const earlyLoginTime = findEarlyLoginTime(this);

    return earlyLoginTime && isTimeReached(earlyLoginTime);
  }

  async saveCodeToLocal({ name, code }) {
    try {
      const filePath = getPathLocalData(this.origin_url); // file path
      const dirPath = path.dirname(filePath); // lấy thư mục cha

      // kiểm tra folder chứa file đã tồn tại chưa
      if (!fs.existsSync(dirPath)) {
        fs.mkdirSync(dirPath, { recursive: true });
      }

      // ghi file
      fs.writeFileSync(
        filePath,
        JSON.stringify({ name, code, time: Date.now() }, null, 2) // format JSON đẹp
      );
    } catch (error) {
      console.log(
        `%cerror [${this.id}] models/api-bid.js line:149`,
        "color: red; display: block; width: 100%;",
        error
      );
    }
  }

  async clearCodeFromLocal() {
    try {
      const filePath = getPathLocalData(this.origin_url); // file path
      const dirPath = path.dirname(filePath); // lấy thư mục cha

      // kiểm tra folder chứa file đã tồn tại chưa
      if (!fs.existsSync(dirPath)) {
        fs.mkdirSync(dirPath, { recursive: true });
      }

      // ghi file
      fs.writeFileSync(
        filePath,
        JSON.stringify({}, null, 2) // format JSON đẹp
      );
    } catch (error) {
      console.log(
        `%cerror [${this.id}] models/api-bid.js line:187`,
        "color: red; display: block; width: 100%;",
        error
      );
    }
  }

  async loadCodeFromLocal() {
    try {
      const filePath = getPathLocalData(this.origin_url);

      if (!fs.existsSync(filePath)) {
        console.warn(
          `%cwarn [${this.id}] models/api-bid.js`,
          "color: orange; display: block; width: 100%;",
          `File not found: ${filePath}`
        );
        return null; // hoặc {} tùy bạn muốn trả gì
      }

      const fileContent = fs.readFileSync(filePath, "utf-8");
      const data = JSON.parse(fileContent);

      return data; // { name, code, time }
    } catch (error) {
      console.error(
        `%cerror [${this.id}] models/api-bid.js`,
        "color: red; display: block; width: 100%;",
        error
      );
      return null;
    }
  }

  async isCodeValid(minutes = 8) {
    try {
      const data = await this.loadCodeFromLocal();
      if (!data || !data.time) {
        return false;
      }

      const now = Date.now();
      const timeDiff = now - data.time; // tính chênh lệch thời gian (ms)

      const validDuration = minutes * 60 * 1000; // phút -> mili giây

      return timeDiff <= validDuration;
    } catch (error) {
      console.error(
        `%cerror [${this.id}] models/api-bid.js`,
        "color: red; display: block; width: 100%;",
        error
      );
      return false;
    }
  }
}
