class ThiefService {
  base64ToFile(base64: string, filename: string, mimeType: string): File {
    // Nếu có tiền tố "data:image/xxx;base64," thì cắt bỏ
    const pureBase64 = base64.includes(",") ? base64.split(",")[1] : base64;

    const byteString = atob(pureBase64);
    const ab = new ArrayBuffer(byteString.length);
    const ia = new Uint8Array(ab);

    for (let i = 0; i < byteString.length; i++) {
      ia[i] = byteString.charCodeAt(i);
    }

    const blob = new Blob([ab], { type: mimeType });
    return new File([blob], filename, { type: mimeType });
  }

  clickByPoint(el: Element) {
    const rect: DOMRect = el.getBoundingClientRect();
    const x: number = rect.left + rect.width / 2;
    const y: number = rect.top + rect.height / 2;

    const target: Element | null = document.elementFromPoint(x, y);
    if (target) {
      target.dispatchEvent(
        new MouseEvent("click", {
          bubbles: true,
          cancelable: true,
          view: window,
        })
      );
    }
  }

  async getElementByXPath(
    xpath: string,
    {
      retryCount = 2,
      delay = 100,
      xpathFallback,
    }: { retryCount?: number; delay?: number; xpathFallback?: string } = {}
  ): Promise<HTMLElement | null> {
    return new Promise((resolve) => {
      let attempts = 0;
      let usingFallback = false;

      const tryFind = () => {
        const el: Node | null = document.evaluate(
          usingFallback && xpathFallback ? xpathFallback : xpath,
          document,
          null,
          XPathResult.FIRST_ORDERED_NODE_TYPE,
          null
        ).singleNodeValue;

        if (el instanceof HTMLElement) {
          resolve(el);
          return;
        }

        attempts++;
        if (attempts < retryCount) {
          setTimeout(tryFind, delay);
        } else {
          if (!usingFallback && xpathFallback) {
            usingFallback = true;
            attempts = 0;
            setTimeout(tryFind, delay);
          } else {
            resolve(null);
          }
        }
      };

      tryFind();
    });
  }

  async imageUrlToBase64(url: string): Promise<string> {
    const response = await fetch(url);
    const blob = await response.blob();

    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onloadend = () => {
        if (typeof reader.result === "string") {
          // Kết quả là data URL (base64)
          resolve(reader.result.split(",")[1]);
        } else {
          reject("Không thể đọc dữ liệu ảnh");
        }
      };
      reader.onerror = reject;
      reader.readAsDataURL(blob);
    });
  }

  getImageExtension(url: string): string | null {
    try {
      const pathname = new URL(url).pathname; // Lấy phần path từ URL
      const match = pathname.match(/\.([a-zA-Z0-9]+)$/); // Tìm đuôi file
      return match ? match[1].toLowerCase() : null;
    } catch {
      // Nếu url không hợp lệ thì fallback sang split
      const parts = url.split("?");
      const path = parts[0];
      const match = path.match(/\.([a-zA-Z0-9]+)$/);
      return match ? match[1].toLowerCase() : null;
    }
  }

  imageLocalToBase64(relativePath: string): Promise<string> {
    return new Promise((resolve, reject) => {
      try {
        // Lấy URL đầy đủ trong extension
        const url = chrome.runtime.getURL(`${relativePath}`);

        // Fetch file
        fetch(url)
          .then((res) => res.blob())
          .then((blob) => {
            const reader = new FileReader();
            reader.onloadend = () => resolve(reader.result as string); // base64
            reader.onerror = reject;
            reader.readAsDataURL(blob);
          })
          .catch(reject);
      } catch (err) {
        reject(err);
      }
    });
  }

  scrollToElement(el: HTMLElement, behavior: ScrollBehavior = "smooth") {
    if (!el) return;
    el.scrollIntoView({
      behavior, // "smooth" hoặc "auto"
      block: "center", // Đưa phần tử ra giữa màn hình
      inline: "nearest",
    });
  }

  getElementPointCoores(el: HTMLElement): { x: number; y: number } | null {
    if (!el) return null;
    const rect = el.getBoundingClientRect();
    const x = rect.left + rect.width / 2;
    const y = rect.top + rect.height / 2;
    return { x, y };
  }

  setInputValue(el: HTMLInputElement | HTMLTextAreaElement, value: string) {
    if (!el) return;

    // Gán giá trị trực tiếp
    el.value = value;

    // Tạo và dispatch sự kiện input
    el.dispatchEvent(new Event("input", { bubbles: true }));

    // Tạo và dispatch sự kiện change (nếu cần)
    el.dispatchEvent(new Event("change", { bubbles: true }));
  }

  writeToInput = async (
    value: string,
    xpath: string,
    xpathFallback?: string
  ) => {
    const el = (await this.getElementByXPath(xpath, {
      xpathFallback,
    })) as HTMLInputElement;

    if (!el) throw new Error("Xpath is not found with value: " + value);

    // Scroll to EL
    this.scrollToElement(el);

    this.clickByPoint(el);

    this.setInputValue(el, value);
  };

  pressEnter(el: HTMLElement) {
    if (!el) {
      throw new Error("Textarea not found:", el);
    }

    el.focus();

    // Chuỗi sự kiện bàn phím
    ["keydown", "keypress", "keyup"].forEach((type) => {
      el.dispatchEvent(
        new KeyboardEvent(type, {
          key: "Enter",
          code: "Enter",
          keyCode: 13,
          which: 13,
          bubbles: true,
          cancelable: true,
        })
      );
    });
  }
}

export const thiefService = new ThiefService();
