/* eslint-disable no-restricted-syntax */
import { htmlToText } from 'html-to-text';

const PDF_SERVICE_API_URL = 'https://service-3rd.autoshopee.com';

/**
 * @param {ArrayBuffer|Buffer} pdfBuffer
 * @returns {void}
 */
const validatePdfBuffer = (pdfBuffer) => {
  if (!pdfBuffer || (pdfBuffer instanceof ArrayBuffer && pdfBuffer.byteLength === 0)) {
    throw new Error('PDF buffer is required');
  }
};

/**
 * @param {ArrayBuffer|Buffer} pdfBuffer
 * @returns {FormData}
 */
const createFormData = (pdfBuffer) => {
  const blob = new Blob([pdfBuffer], { type: 'application/pdf' });
  const formData = new FormData();
  formData.append('file', blob, 'document.pdf');
  return formData;
};

/**
 * @param {string} endpoint
 * @param {ArrayBuffer|Buffer} pdfBuffer
 * @returns {Promise<Response>}
 */
const fetchPdfService = async (endpoint, pdfBuffer) => {
  validatePdfBuffer(pdfBuffer);
  const formData = createFormData(pdfBuffer);

  const response = await fetch(`${PDF_SERVICE_API_URL}/${endpoint}`, {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
    },
    body: formData,
  });

  if (!response.ok) {
    throw new Error(`Failed to fetch PDF service: ${response.statusText}`);
  }

  return response;
};

/**
 * @param {string} key
 * @returns {string}
 */
const normalizeKey = (key) => {
  return key
    .replace(/\s+/g, '_')
    .replace(/([A-Z])/g, '_$1')
    .toLowerCase()
    .replace(/^_+/, '')
    .replace(/_+/g, '_')
    .replace(/_+$/, '');
};

/**
 * @param {string} key
 * @param {string} value
 * @returns {*}
 */
const parseValue = (key, value) => {
  const trimmedValue = value.trim();
  const lowerKey = key.toLowerCase();
  const lowerValue = trimmedValue.toLowerCase();

  if (lowerValue === 'no' || lowerValue === 'yes') {
    return lowerValue === 'yes';
  }

  if (lowerValue === 'none') {
    return null;
  }

  if (lowerKey.includes('date') || lowerKey.includes('time')) {
    const date = new Date(value);
    if (!isNaN(date.getTime())) {
      return date.toISOString();
    }
  }

  if (lowerKey.includes('size')) {
    if (value.includes('x')) {
      const pageSizeMatch = value.match(/(\d+)\s+x\s+(\d+)\s+pts\s+\(([^)]+)\)/);
      if (pageSizeMatch) {
        return {
          width: parseInt(pageSizeMatch[1], 10),
          height: parseInt(pageSizeMatch[2], 10),
          unit: 'pts',
          format: pageSizeMatch[3],
        };
      }
    }

    const fileSizeMatch = value.match(/^(\d+)\s+(\w+)$/);
    if (fileSizeMatch) {
      return {
        value: parseInt(fileSizeMatch[1], 10),
        unit: fileSizeMatch[2],
      };
    }
  }

  if (lowerKey.includes('version')) {
    const versionMatch = value.match(/^(\d+\.?\d*)/);
    if (versionMatch) {
      return parseFloat(versionMatch[1]);
    }
  }

  if (lowerKey.includes('pages') || (lowerKey.includes('page') && lowerKey.includes('rot'))) {
    const numberMatch = value.match(/^(\d+)/);
    if (numberMatch) {
      return parseInt(numberMatch[1], 10);
    }
  }

  if (/^\d+$/.test(trimmedValue)) {
    return parseInt(trimmedValue, 10);
  }

  if (/^\d+\.\d+$/.test(trimmedValue)) {
    return parseFloat(trimmedValue);
  }

  return value;
};

/**
 * @param {string} text
 * @returns {string}
 */
const cleanText = (text) => {
  return text
    .replace(/\[data:image\/[^;]+;base64,[^\]]+\]/g, '')
    .replace(/background\s+image/gi, '')
    .replace(/\s+/g, ' ')
    .replace(/\n\s*\n\s*\n+/g, '\n\n')
    .split('\n')
    .map((line) => line.trim())
    .filter((line) => line.length > 0)
    .join('\n')
    .trim();
};

const parsePdfInfoText = (text) => {
  const lines = text.split('\n').filter((line) => line.trim());

  return lines.reduce((result, line) => {
    const colonIndex = line.indexOf(':');
    if (colonIndex === -1) {
      return result;
    }

    const key = line.substring(0, colonIndex).trim();
    const value = line.substring(colonIndex + 1).trim();

    if (value === '') {
      return result;
    }

    const normalizedKey = normalizeKey(key);
    result[normalizedKey] = parseValue(key, value);
    return result;
  }, {});
};

const getPageNumberFromHtml = (html) => {
  const pageNumbers = new Set();

  const pageCommentMatches = html.matchAll(/<!--\s*Page\s+(\d+)\s*-->/gi);
  for (const match of pageCommentMatches) {
    pageNumbers.add(parseInt(match[1], 10));
  }

  const pageAnchorMatches = html.matchAll(/<a\s+name=["'](\d+)["']/gi);
  for (const match of pageAnchorMatches) {
    pageNumbers.add(parseInt(match[1], 10));
  }

  const pageDivMatches = html.matchAll(/id=["']page(\d+)-div["']/gi);
  for (const match of pageDivMatches) {
    pageNumbers.add(parseInt(match[1], 10));
  }

  if (pageNumbers.size === 0) {
    return 1;
  }

  return Math.max(...Array.from(pageNumbers));
};
/**
 * @param {ArrayBuffer|Buffer} pdfBuffer
 * @returns {Promise<string>}
 */
export const parsePdfToHtml = async (pdfBuffer) => {
  const response = await fetchPdfService('pdftohtml', pdfBuffer);
  return response.text();
};

/**
 * @param {ArrayBuffer|Buffer} pdfBuffer
 * @returns {Promise<string>}
 */
export const parsePdfToText = async (pdfBuffer) => {
  const response = await fetchPdfService('pdftotext', pdfBuffer);
  return response.text();
};

/**
 * @param {ArrayBuffer|Buffer} pdfBuffer
 * @returns {Promise<object>}
 */
export const parsePdfInfo = async (pdfBuffer) => {
  const response = await fetchPdfService('pdfinfo', pdfBuffer);
  const data = await response.text();
  return parsePdfInfoText(data);
};

/**
 * @param {ArrayBuffer|Buffer} pdfBuffer
 * @returns {Promise<{html: string, text: string, page: number}>}
 */
export const parsePdfData = async (pdfBuffer) => {
  validatePdfBuffer(pdfBuffer);

  const html = decodeURI(await parsePdfToHtml(pdfBuffer));
  const page = getPageNumberFromHtml(html);
  const text = cleanText(
    htmlToText(html, {
      ignoreImage: true,
      selectors: [
        { selector: 'img', format: 'skip' },
      ],
    }),
  );

  return {
    html,
    text,
    page,
  };
};
