//import * as avif from '@jsquash/avif'; // TBD
//import * as webp from '@jsquash/webp'; // TBD
import * as jpeg from '@jsquash/jpeg';
import * as png from '@jsquash/png';
import optimise from '@jsquash/oxipng/optimise';
const { __ } = wp.i18n; // Import __() from wp.i18n

(function () {

  const bulkBtn = document.querySelector("input[name='squeeze_bulk']")
  const bulkLogInput = document.querySelector("[name='squeeze_bulk_log']")
  const squeeze_bulk_ids = document.querySelector("input[name='squeeze_bulk_ids']")?.value ?? null;
  const uncompressedIDs = squeeze_bulk_ids ? squeeze_bulk_ids.split(",") : [];

  async function decode(sourceType, fileBuffer) {
    switch (sourceType) {
      //case 'avif':
      //  return await avif.decode(fileBuffer);
      case 'jpeg':
        return await jpeg.decode(fileBuffer);
      case 'png':
        return await png.decode(fileBuffer);
      //case 'webp':
      //  return await webp.decode(fileBuffer);
      default:
        throw new Error(`Unknown source type: ${sourceType}`);
    }
  }

  async function encode(outputType, imageData) {
    const options = JSON.parse(squeeze.options);

    switch (outputType) {
      //case 'avif':
      //  return await avif.encode(imageData);
      case 'jpeg':
        const jpegOptions = {}
        for (const [key, value] of Object.entries(options)) {
          if (key.includes('jpeg')) {
            const keyName = key.replace('jpeg_', '')
            jpegOptions[keyName] = value
          }
        }
        return await jpeg.encode(imageData, jpegOptions);
      case 'png':
        const pngOptions = {}
        for (const [key, value] of Object.entries(options)) {
          if (key.includes('png')) {
            const keyName = key.replace('png_', '')
            pngOptions[keyName] = value
          }
        }
        return await png.encode(imageData, pngOptions);
      //case 'webp':
      //  return await webp.encode(imageData);
      default:
        throw new Error(`Unknown output type: ${outputType}`);
    }
  }

  async function convert(sourceType, outputType, fileBuffer) {
    const imageData = await decode(sourceType, fileBuffer);
    return encode(outputType, imageData);
  }

  function blobToBase64(blob) {
    return new Promise((resolve, _) => {
      const reader = new FileReader();
      reader.onloadend = () => resolve(reader.result);
      reader.readAsDataURL(blob);
    });
  }

  async function showOutput(imageBuffer, outputType) {
    const imageBlob = new Blob([imageBuffer], { type: `image/${outputType}` });
    const base64String = await blobToBase64(imageBlob);

    return base64String;
  }

  async function handleUpload(attachment, isBulk = false, isSingle = false, target = null) {
    const attachmentData = attachment.attributes;
    const url = attachmentData?.originalImageURL ?? attachmentData.url;
    const mime = attachmentData.mime;
    const name = attachmentData.name;
    const filename = attachmentData?.originalImageName ?? attachmentData.filename;
    const attachmentID = attachmentData.id;
    const format = mime.split("/")[1];
    const sourceType = format;
    const outputType = format;
    const options = JSON.parse(squeeze.options);

    let imageBuffer;
    let fileBuffer;
    let base64;

    if (format === "png") {
      const pngOptions = {}
      for (const [key, value] of Object.entries(options)) {
        if (key.includes('png')) {
          const keyName = key.replace('png_', '')
          pngOptions[keyName] = value
        }
      }
      imageBuffer = await fetch(url).then(res => res.arrayBuffer()).then(pngImageBuffer => optimise(pngImageBuffer, pngOptions));
      base64 = await showOutput(imageBuffer, outputType);
    } else {
      let response = await fetch(url);
      let blob = await response.blob();
      let metadata = {
        type: mime
      };
      let imageObj = new File([blob], name, metadata);
      fileBuffer = await imageObj.arrayBuffer();

      /*
      if (window.Worker) {
        //const myWorker = new Worker(new URL(`${squeeze.pluginUrl}/assets/js/worker.js`), { type: "module" });
        const myWorker = new Worker(/* webpackChunkName: "foo-worker" */ /*new URL(`./worker.js`, import.meta.url));
        myWorker.postMessage(
          {
            fileBuffer: fileBuffer, 
            sourceType: sourceType,
            outputType: outputType,
          }
        );
        console.log('Message posted to worker');

        myWorker.onmessage = function(e) {
          console.log('Message received from worker', e.data);
          myWorker.terminate();
        }
      } else {
        console.log('Your browser doesn\'t support web workers.');
      }
      */
      
      imageBuffer = await convert(sourceType, outputType, fileBuffer);
      base64 = await showOutput(imageBuffer, outputType);
    }
    
    let data = {
      action: 'squeeze_update_attachment',
      _ajax_nonce: squeeze.nonce,
      filename: filename,
      type: 'image',
      format: format,
      base64: base64,
      attachmentID: attachmentID,
      url: url,
    }

    jQuery.ajax({
      url: squeeze.ajaxUrl,
      type: 'POST',
      data: data,
      beforeSend: function () {
        console.log('data', data)
        if (isBulk)
          bulkLogInput.value += `#${attachmentID}: ` + __('Compressed successfully, updating...', 'squeeze') + `\r\n`;
      },
      error: function (error) {
        console.error(error)
        if (target) {
          target.closest("td").querySelector(".squeeze_status").innerText = __('An error has occured. Check the console for details.', 'squeeze')
          target.remove();
        }
      },
      success: function (response) {
        console.log(response)
        if (isBulk) {
          if (response.success) {
            bulkLogInput.value += `#${attachmentID}: ` + __('Updated successfully', 'squeeze') + `\r\n===============================\r\n`;
            handleBulkUpload()
          } else {
            bulkLogInput.value += `#${attachmentID}: ${response.data}\r\n===============================\r\n`;
          }
        }
        if (isSingle && target) {
          target.closest("td").querySelector(".squeeze_status").innerText = response.data;
          target.remove();
        }
        if (!isSingle && !isBulk) {
          attachment.set('uploading', false) // resume uploading process
        }
      }
    });
    
  }

  const handleBulkUpload = () => {
    const data = {
      action: 'squeeze_get_attachment',
      _ajax_nonce: squeeze.nonce,
      attachmentID: uncompressedIDs[0],
    }

    if (uncompressedIDs.length === 0) {
      alert(__('All images have been compressed!', 'squeeze'))
      bulkBtn.remove();
      location.reload();
      return;
    }

    bulkLogInput.value += `attachment #${uncompressedIDs[0]}: start compressing...\r\n`;

    jQuery.ajax({
      url: squeeze.ajaxUrl,
      type: 'POST',
      data: data,
      error: function (error) {
        console.error(error)
      },
      success: function (response) {
        //console.log(response)
        if (response.success) {
          const responseData = response.data;
          const attachment = {
            attributes: {
              url: responseData.url,
              mime: responseData.mime,
              name: responseData.name,
              filename: responseData.filename,
              id: responseData.id,
            }
          }
          //console.log(attachment, 'attachment')
          uncompressedIDs.shift();
          handleUpload(attachment, true)
        } else {
          console.error(response.data)
        }
      }
    });
  }

  function handleRestore(attachmentID, target) {
    let data = {
      action: 'squeeze_restore_attachment',
      _ajax_nonce: squeeze.nonce,
      attachmentID: attachmentID,
    }

    jQuery.ajax({
      url: squeeze.ajaxUrl,
      type: 'POST',
      data: data,
      beforeSend: function () {
        target.disabled = true;
        target.innerText = __('Restore in process...', 'squeeze')
      },
      error: function (error) {
        console.error(error)
        target.closest("td").querySelector(".squeeze_status").innerText = __('An error has occured. Check the console for details.', 'squeeze')
        target.remove();
      },
      success: function (response) {
        //console.log(response)
        target.closest("td").querySelector(".squeeze_status").innerText = response.data; //__('Restored successfully', 'squeeze')
        target.remove();
      }
    });
  }

  // Handle single compress button click
  const handleSingleBtnClick = (event) => {
    const attachmentID = event.target.dataset.attachment;

    wp?.media?.attachment(attachmentID).fetch().then(function (data) {
      const attachment = {
        attributes: data
      }
      handleUpload(attachment, false, true, event.target)
    });
  }

  // Handle restore button click
  const handleRestoreBtnClick = (event) => {
    const attachmentID = event.target.dataset.attachment;
    handleRestore(attachmentID, event.target)
  }

  /**
   * Handle single buttons click
   */
  function handleSingleButtonsClick() {
    document.addEventListener("click", (e) => {
      //console.log(e.target, 'e.target')
      const singleBtnName = 'squeeze_compress_single';
      const restoreBtnName = 'squeeze_restore';
      if (e.target.getAttribute("name") === singleBtnName) {
        e.target.disabled = true;
        e.target.innerText = __('Compressing...', 'squeeze')
        handleSingleBtnClick(e)
      }
      if (e.target.getAttribute("name") === restoreBtnName) {
        e.target.disabled = true;
        handleRestoreBtnClick(e)
      }
    })
  }

  handleSingleButtonsClick()


  /**
   * Handle bulk button click
   */
  bulkBtn?.addEventListener("click", (event) => {
    if (uncompressedIDs.length === 0) {
      return;
    }

    bulkBtn.disabled = true;
    handleBulkUpload()

  })

  // https://wordpress.stackexchange.com/a/131295/186146 - override wp.Uploader.prototype.success
  jQuery.extend(wp?.Uploader?.prototype, {
    success: function (attachment) {
      //console.log(attachment, 'success');
      const options = JSON.parse(squeeze.options);
      const isAutoCompress = options.auto_compress;
      let isImage = attachment.attributes.type === 'image' &&
        (attachment.attributes.subtype === 'jpeg' || attachment.attributes.subtype === 'png')

      if (isImage && isAutoCompress) {
        // set 'uploading' param to true, to pause the uploading process
        attachment.set('uploading', true)
        handleUpload(attachment)
      }
    },
  });
})();

//console.log(JSON.parse(squeeze.options), 'squeeze.options')