/* eslint-disable @typescript-eslint/no-explicit-any */
import { delay, delayRD } from "@/features/app";
import type { IPost, ISyncItem } from "@/lib/utils";
import { thiefService } from "./thief.service";

class FacebookService {
  sellingPath = "https://www.facebook.com/marketplace/you/selling";
  marketPath = "https://www.facebook.com/marketplace";
  createItem = "https://www.facebook.com/marketplace/create/item";
  editItem = "https://www.facebook.com/marketplace/edit";

  selectors = {
    file__image_input: 'input[type="file"]',
    next_btn:
      "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[5]/div/div/div",
    update_btn:
      "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[4]/div/div/div",
    publish_btn:
      "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[4]/div[2]/div/div",
    // products:
    //   "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[2]/div/div/div[2]/div[1]/div/div[2]/div/div/span/div/div",
    // products_fallback:
    //   "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[2]/div/div/div[2]/div[1]/div/div[3]/div/div/span/div[2]/div",
    option_btn:
      "/html/body/div[1]/div/div[1]/div/div[4]/div/div/div[1]/div/div[2]/div/div/div/div/div/div/div[3]/div/div/div/div/div[1]/div",
    option_btn_fallback:
      "/html/body/div[1]/div/div[1]/div/div[4]/div/div/div[1]/div/div[2]/div/div/div/div[3]/div[2]/div/div[2]/div[1]",
    close_btn_modal_feedback:
      "/html/body/div[1]/div/div[1]/div/div[4]/div/div/div[1]/div/div[2]/div/div/div/div[2]/div",
    images_container:
      "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[2]/div[1]/div[2]/div/div/div[3]/div[2]/div",
    description_edit_input:
      "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[9]/div/div/div[2]/div/div/div/label/div/div/textarea",
    sku_edit_input:
      "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[9]/div/div/div[5]/div/div/div[1]/label/div/input",
    new_item_btn:
      "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[1]/div/div[3]/div[1]/div[2]/div/div/div[7]/a/div",
    item_for_sell:
      "/html/body/div[1]/div/div[1]/div/div[5]/div/div/div[3]/div[2]/div[2]/div/div/div[2]/div[1]/div/span/div/div/div[1]/div/div",
    market_container: '[aria-label="Marketplace"]',
    collection_marketplace:
      '[aria-label="Collection of your Marketplace items"]',
  };

  findInputByTitle(title: string, type: "input" | "textarea" = "input") {
    const el = thiefService.findNestedElement(
      this.selectors.market_container,
      "span",
      title
    );

    if (!el) throw new Error("Not found input by title: " + title);

    return thiefService.findElInParent(el, type) as HTMLInputElement;
  }

  clearImages = async () => {
    document
      .querySelectorAll('[aria-label="Remove"]')
      .forEach((item) => (item as any)?.click());
  };

  uploadImages = async (item: IPost) => {
    // Tạo DataTransfer để giả lập FileList
    const dt: DataTransfer = new DataTransfer();

    for (const image of item.images) {
      const base64 = await thiefService.imageUrlToBase64(image);

      const file = thiefService.base64ToFile(
        base64,
        item.sku,
        thiefService.getImageExtension(image) || "jpg"
      );

      dt.items.add(file);
    }

    // Tìm input file của Facebook
    const input: HTMLInputElement | null = document.querySelector(
      this.selectors.file__image_input
    );

    if (input) {
      // Gán file vào input
      input.files = dt.files;

      // Gửi event change
      input.dispatchEvent(new Event("change", { bubbles: true }));
    } else {
      console.error("Không tìm thấy input[type='file']");
    }
  };

  chooseSelect = async (
    value: string,
    title: string,
    dropContainer: string = '[aria-label="Dropdown menu"]'
  ) => {
    const el = thiefService.findNestedElement(
      this.selectors.market_container,
      "span",
      title
    );

    thiefService.scrollToElement(el!);
    await delayRD(500, 600); // delay sau scroll

    el?.click();
    await delayRD(500, 600); // delay sau click

    const matchingChild = thiefService.findNestedElement(
      dropContainer,
      "span",
      value
    );
    await delayRD(500, 600); // delay sau khi tìm

    if (!matchingChild) throw new Error(`No child found with text "${value}"`);

    thiefService.scrollToElement(matchingChild);
    await delayRD(500, 600); // delay sau scroll đến child

    matchingChild.click();
    await delayRD(500, 600); // delay sau click child
  };

  chooseLocation = async (value: string) => {
    const input = this.findInputByTitle("location");

    await thiefService.writeToInput(value, input);

    await delay(600);

    // input.click();

    const matchingChilds =
      document.querySelector('[role="listbox"]')?.querySelectorAll("li") || [];

    const matchingChild = Array.from(matchingChilds).find((item) =>
      item.innerHTML.trim().toLowerCase().includes(value.toLowerCase())
    );

    if (!matchingChild) throw new Error(`No child found with text "${value}"`);

    thiefService.scrollToElement(matchingChild);

    await delay(400);
    thiefService.clickByPoint(matchingChild);
  };

  writeTags = async (tags: string[]) => {
    const input = this.findInputByTitle("product tags", "textarea");
    if (!input) throw new Error("Input is not found");

    thiefService.scrollToElement(input);

    await delay(500);

    for (const tag of tags) {
      await thiefService.writeToInput(tag, input);

      await delay(300);

      thiefService.pressEnter(input);
    }
  };

  clickNext = async () => {
    const btn = await thiefService.getElementByXPath(this.selectors.next_btn);

    if (!btn) throw new Error("Next button is not found");

    thiefService.clickByPoint(btn);
  };

  clickUpdate = async () => {
    const btn = await thiefService.getElementByXPath(this.selectors.update_btn);

    if (!btn) throw new Error("Next button is not found");

    thiefService.clickByPoint(btn);
  };

  clickPublist = async () => {
    const btn = await thiefService.getElementByXPath(
      this.selectors.publish_btn
    );

    if (!btn) throw new Error("Publist button is not found");

    thiefService.clickByPoint(btn);
  };

  /**
   * B1. Upload images
   * B2. Write title
   * B3. Write price
   * B4. Select category
   * B5. Select condition
   * .....
   */
  handlePublist = async (item: IPost) => {
    await delayRD(600, 1000);
    // B1. Upload images
    await this.uploadImages(item);

    await delayRD(600, 1000);
    // B2. Write title

    const title_input = this.findInputByTitle("title");

    thiefService.writeToInput(item.title, title_input);

    await delayRD(600, 1000);

    // B3. Write price
    const price_input = this.findInputByTitle("price");
    thiefService.writeToInput(String(item.price), price_input);

    await delayRD(600, 1000);

    // // B4. Select category
    await this.chooseSelect(item.category, "category");

    await delayRD(600, 1000);

    // // B5. Select condition
    await this.chooseSelect(
      item.condition,
      "condition",
      '[aria-label="Select an option"]'
    );

    if (item.brand) {
      await delayRD(600, 1000);

      // B6. Write brand
      const brand_input = this.findInputByTitle("brand");
      await thiefService.writeToInput(item.brand, brand_input);
    }

    await delayRD(600, 1000);

    // B7. Write description
    const description_input = this.findInputByTitle("description", "textarea");
    await thiefService.writeToInput(item.description, description_input);

    await delayRD(600, 1000);

    await this.writeTags(item.tags);

    await delayRD(600, 1000);

    // B8. Write sku
    const sku_input = this.findInputByTitle("sku");
    await thiefService.writeToInput(item.sku, sku_input);

    if (item?.location) {
      await delayRD(600, 1000);

      await this.chooseLocation(item.location);
    }

    await delayRD(300, 500);

    await this.clickNext();

    // await delayRD(300, 500);

    // await this.clickPublist();

    return true;
  };

  /**
   * B1. Upload images
   * B2. Write title
   * B3. Write price
   * B4. Select category
   * B5. Select condition
   * .....
   */
  handleRePublist = async (item: IPost) => {
    await thiefService.waitForElement(
      '[aria-label="Collection of your Marketplace items"]'
    );

    // Lấy tất cả các item trong menu (thường là 'Edit', 'Delete', ...)
    const items = await this.getOptionEls(item);

    // // Tìm item chứa chữ "delete"
    this.clickItemInList(items, "edit");

    // Delay 1 giây để modal xác nhận xóa hiện ra
    await delay(1000);

    // CHỜ tới khi URL đổi sang sellingPath
    await this.waitForPageReady(this.editItem, this.selectors.market_container);

    await delayRD(1000, 2000);

    await this.clearImages();

    await delayRD(600, 1000);

    // B1. Upload images
    await this.uploadImages(item);

    await delayRD(600, 1000);
    // B2. Write title

    const title_input = this.findInputByTitle("title");

    thiefService.writeToInput(item.title, title_input);

    await delayRD(600, 1000);

    // B3. Write price
    const price_input = this.findInputByTitle("price");
    thiefService.writeToInput(String(item.price), price_input);

    await delayRD(600, 1000);

    // // B4. Select category
    await this.chooseSelect(item.category, "category");

    await delayRD(600, 1000);

    // // B5. Select condition
    await this.chooseSelect(
      item.condition,
      "condition",
      '[aria-label="Select an option"]'
    );

    await delayRD(600, 1000);

    // B7. Write description
    const description_input = this.findInputByTitle("description", "textarea");
    await thiefService.writeToInput(item.description, description_input);

    await delayRD(600, 1000);

    await this.writeTags(item.tags);

    await delayRD(600, 1000);

    if (item?.location) {
      await delayRD(600, 1000);

      await this.chooseLocation(item.location);
    }

    return true;
  };

  async getInfo(): Promise<any | null> {
    const TTL = 2 * 60 * 60 * 1000; // 2 tiếng

    try {
      const now = Date.now();

      // 1. Lấy cache từ storage
      const cached: { data: any; timestamp: number } | null = await new Promise(
        (resolve) => {
          chrome.storage.local.get("meCache", (res) => {
            resolve(res.meCache ? JSON.parse(res.meCache) : null);
          });
        }
      );

      // 2. Nếu cache còn hạn thì trả về ngay
      if (cached && now - cached.timestamp < TTL) {
        return cached.data;
      }

      // 3. Nếu không có cache hoặc hết hạn, fetch API
      const response = await fetch("/me");
      if (!response.ok)
        throw new Error(`HTTP error! status: ${response.status}`);

      // 4. Lưu cache vào storage
      chrome.storage.local.set({
        meCache: JSON.stringify({
          data: { url: response.url },
          timestamp: now,
        }),
      });

      return response;
    } catch (err) {
      console.error("Failed to get /me:", err);
      return null;
    }
  }

  getProductContainer() {
    const items = document.querySelectorAll(
      '[aria-label="Collection of your Marketplace items"] span > div > div'
    );

    const filtered = Array.from(items).filter((el) => {
      return el.querySelector("span > div > div") && el.classList.length > 0;
    });

    return filtered.length > 0 ? filtered[0] : null;
  }

  getProducts = async (): Promise<ISyncItem[]> => {
    // Lấy container sản phẩm
    const productContainer = this.getProductContainer();

    if (!productContainer) {
      throw new Error("List element has changed. Please connect to DEV");
    }

    // Lấy thông tin phụ trợ (vd: seller info, webname, config...)
    const info = await this.getInfo();

    // Trích xuất listings từ container duy nhất này
    return this.extractListings(
      productContainer as HTMLDivElement,
      info
    ) as ISyncItem[];
  };

  extractListings(productsEl: HTMLElement, info?: Response | null) {
    const children = Array.from(productsEl.children);

    return children.map((child) => {
      // Lấy title
      const titleEl = child.querySelector('span[dir="auto"], div[dir="auto"]');
      const title = titleEl?.textContent?.trim() || "";

      const els = document.querySelectorAll(`[aria-label="${title}"]`);

      // Chuyển sang mảng và filter
      const filtered = Array.from(els).filter(
        (el) => !el.querySelector("img")
      )[0];

      const priceEl = thiefService.findNestedIcElement(filtered, "span", "AU$");

      const priceMatch = priceEl?.textContent?.match(/[\d,]+(?:\.\d+)?/);
      const price = priceMatch
        ? parseFloat(priceMatch[0].replace(/,/g, ""))
        : 0;

      return { title, price, el: productsEl, url_info: info?.url };
    });
  }

  closeTab = async (data: IPost) => {
    chrome.runtime.sendMessage({
      type: "close-tab",
      payload: data,
    });
  };

  clickOptionOfProduct(data: IPost) {
    // Tìm nút "More options" cho sản phẩm đó
    const optionEl = document.querySelector(
      `[aria-label="More options for ${data.title}"]`
    );

    if (!optionEl)
      throw new Error(
        `Not found option buttin in product ${`[aria-label="More options for ${data.title}"]`}, ID: ${
          data.id
        }`
      );

    thiefService.scrollToElement(optionEl as any);

    // Click vào nút "More options" để mở menu
    (optionEl as any).click?.();
  }

  async getOptionEls(data: IPost) {
    this.clickOptionOfProduct(data);

    // Delay 2 giây để menu hiển thị hoàn toàn
    await delay(2000);

    // Lấy tất cả các item trong menu (thường là 'Edit', 'Delete', ...)
    const items = Array.from(document.querySelectorAll('[role="menuitem"]'));

    return items;
  }

  clickItemInList(items: Element[], innerText: string) {
    // Tìm item chứa chữ "delete"
    const item = items.find((item) =>
      item.textContent.toLocaleLowerCase().includes(innerText)
    );

    if (!item) throw new Error(`Not found item ${innerText} in options list`);

    // Click vào item "Delete"
    (item as any).click?.();
  }

  getItemInList(items: Element[], innerText: string) {
    // Tìm item chứa chữ "delete"
    const item = items.find((item) =>
      item.textContent.toLocaleLowerCase().includes(innerText)
    );

    if (!item) throw new Error(`Not found item ${innerText} in options list`);

    return item;
  }

  handleDelete = async (payload: IPost) => {
    // Lấy tất cả các item trong menu (thường là 'Edit', 'Delete', ...)
    const items = await this.getOptionEls(payload);

    // // Tìm item chứa chữ "delete"
    this.clickItemInList(items, "delete");

    // Delay 1 giây để modal xác nhận xóa hiện ra
    await delay(1000);

    // Lấy nút "Options" trong modal (hoặc fallback nếu xpath chính không tìm thấy)
    const confirmBtn = await thiefService.getElementByXPath(
      this.selectors.option_btn,
      {
        xpathFallback: this.selectors.option_btn_fallback,
      }
    );

    // Click vào nút "Options" trong modal nếu tìm thấy
    confirmBtn?.click();

    // Lấy nút "Close" của modal feedback (nếu có) để đóng modal sau khi xóa
    const closeBtnModalFeedback = await thiefService.getElementByXPath(
      this.selectors.close_btn_modal_feedback
    );

    closeBtnModalFeedback?.click();

    // Gọi API backend để đánh dấu sản phẩm đã xóa (published = false)
    // await productApi.finistDelete(payload, { published: false });

    // Gửi message đến background/content script thông báo là delete đã xong
    chrome.runtime.sendMessage({ type: "delete-done" });
  };

  waitForUrlContains(path: string, timeout = 10000) {
    return new Promise<void>((resolve, reject) => {
      const start = Date.now();
      const check = () => {
        if (window.location.href.includes(path)) {
          resolve();
        } else if (Date.now() - start > timeout) {
          reject(new Error("Timeout waiting for URL change"));
        } else {
          setTimeout(check, 500);
        }
      };
      check();
    });
  }

  waitForPageReady(path: string, selector: string, timeout = 15000) {
    return new Promise<void>((resolve, reject) => {
      const start = Date.now();

      const check = async () => {
        // Đúng URL + DOM có dấu hiệu đã render
        if (
          window.location.href.includes(path) &&
          // document.querySelector('[role="main"]') // thay bằng selector chắc chắn có trong selling page
          document.querySelector(selector)
        ) {
          resolve();
        } else if (Date.now() - start > timeout) {
          reject(new Error("Timeout waiting for selling page ready"));
        } else {
          setTimeout(check, 500);
        }
      };

      // chạy liền để check ngay
      check();
    });
  }

  extractMarketplaceItemId(url: string): string | null {
    const match = url.match(/\/marketplace\/item\/(\d+)/);
    return match ? match[1] : null;
  }

  handleGetPublistID = async (payload: IPost) => {
    // Lấy tất cả sản phẩm hiện tại trên Facebook Marketplace
    const products = await facebookService.getProducts();

    // Tìm sản phẩm khớp với title và price từ payload
    const product = products.find((product) => {
      return product.title == payload.title && product.price == payload.price;
    });

    // Nếu không tìm thấy sản phẩm nào khớp thì kết thúc
    if (!product) return;

    const el = product.el; // element HTML đại diện cho sản phẩm trên trang

    // Lấy tất cả các item trong menu (thường là 'Edit', 'Delete', ...)
    const items = await this.getOptionEls(payload);

    const item = this.getItemInList(items, "view listing");

    const publistID = this.extractMarketplaceItemId((item as any)["href"]);

    this.clickOptionOfProduct(payload);

    return publistID;
  };

  async gotoPublist() {
    const btn = await thiefService.getElementByXPath(
      this.selectors.new_item_btn
    );

    btn?.click();

    await delayRD(400, 800);

    const forSell = await thiefService.getElementByXPath(
      this.selectors.item_for_sell
    );

    forSell?.click();
  }

  async gotoSell() {
    const btn = document.querySelector('[href="/marketplace/you/selling/"]');

    (btn as any)?.click();
  }
}

export const facebookService = new FacebookService();
