import * as fs from "fs";
import * as path from "path";
import { PuppeteerScreenRecorder } from "puppeteer-screen-recorder";
import { outBid, uploadRecord } from "../system/apis/bid.js";
import BID_TYPE from "../system/bid-type.js";
import browser from "../system/browser.js";
import CONSTANTS from "../system/constants.js";
import { getPathProfile, randomDelayWithMeta } from "../system/utils.js";
import { Bid } from "./bid.js";
import { unlink } from "fs/promises";
export class ProductBid extends Bid {
  // value 'live' | 'sandbox'
  static MODE_KEY = "mode_key";

  // value is minutes esg: arrival_offset_seconds of web bid parent
  static ARRIAVAL_OFFSET_SECONDS_LIVE = "arrival_offset_seconds_live";
  static ARRIAVAL_OFFSET_SECONDS_SANDBOX = "arrival_offset_seconds_sandbox";

  // value is minutes esg: early_tracking_seconds of web bid parent
  static EARLY_TRACKING_SECONDS = "early_tracking_seconds";
  static EARLY_TRACKING_SECONDS_LIVE = `${this.EARLY_TRACKING_SECONDS}_live`;
  static EARLY_TRACKING_SECONDS_SANDBOX = `${this.EARLY_TRACKING_SECONDS}_sandbox`;

  id;
  max_price;
  model;
  lot_id;
  plus_price;
  close_time;
  first_bid;
  quantity;
  created_at;
  updated_at;
  histories;
  start_bid_time;
  parent_browser_context;
  web_bid;
  current_price;
  name;
  reserve_price;
  update;
  metadata;
  recorder;
  name_record;

  constructor({
    url,
    max_price,
    plus_price,
    model,
    first_bid = false,
    id,
    created_at,
    updated_at,
    quantity = 1,
    histories = [],
    close_time,
    lot_id,
    start_bid_time,
    web_bid,
    current_price,
    reserve_price,
    name,
    metadata,
  }) {
    super(BID_TYPE.PRODUCT_TAB, url);
    this.max_price = max_price || 0;
    this.model = model;
    this.plus_price = plus_price || 0;
    this.first_bid = first_bid;
    this.id = id;
    this.created_at = created_at;
    this.updated_at = updated_at;
    this.quantity = quantity;
    this.histories = histories;
    this.close_time = close_time;
    this.lot_id = lot_id;
    this.start_bid_time = start_bid_time;
    this.web_bid = web_bid;
    this.current_price = current_price;
    this.name = name;
    this.reserve_price = reserve_price;
    this.metadata = metadata;
  }

  setNewData({
    url,
    max_price,
    plus_price,
    model,
    first_bid = false,
    id,
    created_at,
    updated_at,
    quantity = 1,
    histories = [],
    close_time,
    lot_id,
    start_bid_time,
    web_bid,
    current_price,
    reserve_price,
    name,
    metadata,
  }) {
    this.max_price = max_price || 0;
    this.model = model;
    this.plus_price = plus_price || 0;
    this.first_bid = first_bid;
    this.id = id;
    this.created_at = created_at;
    this.updated_at = updated_at;
    this.quantity = quantity;
    this.histories = histories;
    this.close_time = close_time;
    this.lot_id = lot_id;
    this.start_bid_time = start_bid_time;
    this.web_bid = web_bid;
    this.url = url;
    this.current_price = current_price;
    this.name = name;
    this.reserve_price = reserve_price;
    this.metadata = metadata;
  }

  puppeteer_connect = async () => {
    if (!this.parent_browser_context) {
      console.log(
        `❌ Connect fail. parent_browser_context is null: ${this.id}`
      );
      return;
    }

    const context = await browser.createBrowserContext();

    const statusInit = await this.restoreContext(context);

    if (!statusInit) {
      console.log(`⚠️ Restore failed.`);
      return;
    }

    const page = await context.newPage();

    this.page_context = page;
    this.browser_context = context;
  };

  async restoreContext(context) {
    const filePath = getPathProfile(this.web_bid.origin_url);

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

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

    // Restore Cookies
    await context.setCookie(...contextData.cookies);

    return true;
  }

  async gotoLink() {
    const page = this.page_context;

    if (page.isClosed()) {
      console.error("❌ Page has been closed, cannot navigate.");
      return;
    }

    console.log("🔄 Starting the bidding process...");

    try {
      await page.goto(this.url, { waitUntil: "networkidle2" });
      console.log(`✅ Navigated to: ${this.url}`);

      await page.bringToFront();
      await page.setUserAgent(
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
      );
      console.log("👀 Brought the tab to the foreground.");
    } catch (error) {
      console.error("❌ Error during navigation:", error);
    }
  }

  getMode = () => {
    return (
      this.metadata.find((item) => item.key_name === ProductBid.MODE_KEY)
        ?.value || "live"
    );
  };

  getEarlyTrackingSeconds = () => {
    const mode = this.getMode();

    return (
      this.metadata.find(
        (item) =>
          item.key_name === `${ProductBid.EARLY_TRACKING_SECONDS}_${mode}`
      )?.value || this.web_bid.early_tracking_seconds
    );
  };

  isSandbox() {
    return this.getMode() !== "live";
  }

  async delayForAction() {
    // Thực thi hành động
    console.log(`[${this.id}] 🚀 Executing action`);
    const { wait, delay } = randomDelayWithMeta();

    console.log(
      `[${this.id}] ⏳ Delay for action: ${(delay / 1000).toFixed(2)} seconds`
    );

    await wait;

    console.log(`[${this.id}] ✅ Finished delay`);
  }

  async close() {
    await outBid(this.id);
  }

  async startRecordSandbox() {
    if (
      !this.page_context ||
      !this.name ||
      this.recorder ||
      this.getMode() === "live"
    )
      return;

    const dirPath = CONSTANTS.RECORD_VIDEO_PATH;

    // 📁 Kiểm tra và tạo thư mục nếu chưa có
    if (!fs.existsSync(dirPath)) {
      fs.mkdirSync(dirPath, { recursive: true }); // recursive để tạo nested folder nếu cần
      console.log("📁 Created recording folder:", dirPath);
    }

    this.name_record = `${this.id}_${this.name}_${new Date().getTime()}.mp4`;

    const filePath = path.join(dirPath, this.name_record);

    this.recorder = new PuppeteerScreenRecorder(this.page_context);
    await this.recorder.start(filePath);
  }

  async stopRecordSandbox() {
    if (!this.recorder || this.getMode() === "live") return;

    await this.recorder.stop();

    const filePath = path.join(CONSTANTS.RECORD_VIDEO_PATH, this.name_record);

    const result = await uploadRecord(this, filePath);

    return result;
  }

  ACTION_URL(options = { type: "action" }) {
    return `${process.env.BASE_URL}bids/hook-action?id=${this.id}&type=${options.type}`;
  }
}
