import { delay } from '../../utils.js'
import path from 'path';
import { fileURLToPath } from 'node:url';
import Tesseract from 'tesseract.js';

export default class TesseractOcr {
    constructor() {
      this.initComplete = false;
      this.init();
    }

    async init(){
      const __filename = fileURLToPath(import.meta.url);
      const __dirname = path.dirname(__filename);
      console.log("__dirname: " + __dirname)
      this.worker = await Tesseract.createWorker({
        langPath: path.join(__dirname, 'lang-data'),
        // logger: m => console.log(m)
      });
      await this.worker.load();
      await this.worker.loadLanguage("eng");
      await this.worker.initialize("eng", Tesseract.OEM.TESSERACT_ONLY);
      this.initComplete = true;
    }

    async getOcrlines(searchText, imagePath) {
      let resarr = [];
      // get unique characters for OCR whitelist
      let searchTextNoWs = searchText.replace(/\s+/g, '').toLowerCase();
      let chars = searchTextNoWs + searchTextNoWs.toUpperCase();
      chars = chars.split('').filter(function(item, pos, self) {
        return self.indexOf(item) == pos;}).join('');
      if (imagePath) {
        while (!this.initComplete){
          await delay(100);
        }
        await this.worker.setParameters({
          tessedit_char_whitelist: chars,
        });
        let res = await this.worker.recognize(imagePath);
        if (res.data.blocks) {
          res.data.blocks.forEach(block => {
            if (block.text.replace(/\s+/g, '').toLowerCase().includes(searchTextNoWs)){
              block.paragraphs.forEach(paragraph => {
                if (paragraph.text.replace(/\s+/g, '').toLowerCase().includes(searchTextNoWs)){
                  paragraph.lines.forEach(line => {
                    if (line.text.replace(/\s+/g, '').toLowerCase().includes(searchTextNoWs)){
                      resarr.push(line);
                    }
                  });
                }
              });
            }
          });
        }
        await this.worker.terminate();
      }
      return resarr;
    }

    getCentre(bbox){
        if (bbox){
          return { x: (bbox.x0 + Math.round((bbox.x1 - bbox.x0) /2)) ,
                   y: (bbox.y0 + Math.round((bbox.y1 - bbox.y0) /2)) };
        } else {
            throw new Error("The given ocrResult object did not have bbox in calculateCentre of TesseractOcr");
        }
    }

    getTopLeft(bbox){
      if (bbox){
        return {x: bbox.x0,
                y: bbox.y0};
      } else {
          throw new Error("The given ocrResult object did not have bbox in calculateCentre of TesseractOcr");
      }
    }

    getTopCentre(bbox){
      if (bbox){
        return {x:(bbox.x0 + Math.round((bbox.x1 - bbox.x0) /2)) ,
                y: bbox.y0};
      } else {
          throw new Error("The given ocrResult object did not have bbox in calculateCentre of TesseractOcr");
      }
    }

    getBottomRight(bbox){
      if (bbox){
        return {x: bbox.x1,
                y: bbox.y1};
      } else {
          throw new Error("The given ocrResult object did not have bbox in calculateCentre of TesseractOcr");
      }
    }

    getBottomCentre(bbox){
      if (bbox){
        return {x: (bbox.x0 + Math.round((bbox.x1 - bbox.x0) /2)),
                y:  bbox.y1};
      } else {
          throw new Error("The given ocrResult object did not have bbox in calculateCentre of TesseractOcr");
      }
    }

    async getFirstPositionBbox(searchText, imagePath) {
      let wrapped_promise = new Promise(async (resolve) => {
        setTimeout(() => resolve(new Error('Error TesseractOcr getOcrlines: Function timed out after 2 minutes')), 120000);
        let result = await this.getOcrlines(searchText, imagePath);
        resolve(result);
      });

      let result = await wrapped_promise;

      if (result instanceof Error) {
        console.error(result.message);
        throw result
      } else if (result && result.length && result.length > 0 && result[0].bbox) {
        return result[0].bbox;
      } else {
        throw new Error("Error TesseractOcr getOcrlines: Text not found");
      }
    }
}
