"""
Module for converting files to PDF format using the PDFTron (Apryse) SDK.

Functions:
    convert_file_to_pdf(input_file_path: str, pdf_file_path: str, pdftron_license_key: str)
        Converts a supported input document into a PDF and saves it.
"""

import os

import pymupdf

# pylint: disable=E0611
from PDFNetPython3 import Convert, OfficeToPDFOptions, PDFDoc, PDFNet, SDFDoc

from config import Config, get_logger  # pylint: disable=E0401

logger = get_logger(__name__)


def list_embedded_fonts(pdf_path):
    """
    List embedded fonts in a PDF file.

    This function opens a PDF file and extracts all embedded fonts used in the document.
    It returns a list of fonts with their names, whether they are embedded, and the file name
    of the embedded font if it exists.
    """
    try:
        doc = pymupdf.open(pdf_path)
        # Consider using enumerate instead of iterating with range and len (consider-using-enumerate)
        for _, page in enumerate(doc):
            font_list = page.get_fonts(full=True)
            for font in font_list:
                logger.debug(f"FONT: Fonts in file: {font}")
    except Exception as e:  # pylint: disable=W0718
        logger.error(f"Failed to list embedded fonts: {e}", exc_info=True)


def convert_file_to_pdf(input_file_path: str, pdf_file_path: str, pdftron_license_key: str, config: Config):
    """
    Converts a document to PDF format using the PDFTron (Apryse) SDK.

    This function initializes the PDFTron SDK with the provided license key, loads the input file,
    performs the conversion to PDF, and saves the resulting PDF to the specified output path.
    It supports Microsoft Office documents (.docx, .xlsx, .pptx).

    Args:
        input_file_path (str): The path to the source file to be converted (e.g., /./users.docx).
        pdf_file_path (str): The destination path where the resulting PDF file will be saved.
        pdftron_license_key (str): PDFTron (Apryse) license key required for SDK initialization.

    Returns:
        bool: True if the conversion is successful.

    Raises:
        FileNotFoundError: If the input file does not exist.
        Exception: For any other unexpected errors during conversion.

    Example:
        >>> convert_file_to_pdf("input.docx", "output.pdf", "YOUR_PDFTRON_LICENSE_KEY")
        True

    """
    pdf_init_done = False
    try:
        # Check for license key
        if not pdftron_license_key or not isinstance(pdftron_license_key, str):
            logger.error("PDFTron license key is missing or invalid.")
            raise ValueError("PDFTron license key is missing or invalid.")

        # Check if input file exists
        if not os.path.isfile(input_file_path):
            logger.error(f"Input file does not exist: {input_file_path}")
            raise FileNotFoundError(f"Input file does not exist: {input_file_path}")

        # Make sure env var FONTCONFIG_PATH is set to path of fonts folder
        # so fonts folder gets detected by the pdfnet initialization
        fontconfig_path = f"{config.extraction.ai_font_mount_folder}/fonts"

        # Check if fonts folder exists
        if not os.path.isdir(fontconfig_path):
            logger.error(f"FONT: Fonts folder does not exist: {fontconfig_path}")
            raise FileNotFoundError(f"Fonts folder does not exist: {fontconfig_path}")

        # Check if fonts.conf file exists in the fonts folder
        fonts_conf_path = f"{fontconfig_path}/fonts.conf"
        if not os.path.isfile(fonts_conf_path):
            logger.error(f"FONT: Fonts.conf file does not exist: {fonts_conf_path}")
            raise FileNotFoundError(f"Fonts.conf file does not exist: {fonts_conf_path}")

        # Read fonts.conf file and log its contents
        with open(fonts_conf_path, "r", encoding="utf-8") as file:
            logger.debug(f"FONT: Fonts.conf file contents: {file.read()}")

        # Log the .ttf files in the fonts folder and log number of files found
        font_files = os.listdir(fontconfig_path)
        ttf_files_counter = 0
        for file in font_files:
            if file.endswith(".ttf"):
                ttf_files_counter += 1
                logger.debug(f"FONT: Font file found: {file}")
        logger.debug(f"FONT: Number of .ttf files found: {ttf_files_counter}")

        os.environ["FONTCONFIG_PATH"] = fontconfig_path

        # Initialize PDFTron SDK
        PDFNet.Initialize(pdftron_license_key)
        pdf_init_done = True
        logger.info("PDFTron SDK Initialized")

        # Perform the conversion
        pdf_doc = PDFDoc()
        logger.info(f"Converting {input_file_path} to PDF!")
        # This method will convert to pdf only if the input file is an office file, i.e. PPT, XLS, DOC,
        # else it will raise error.
        options = OfficeToPDFOptions()
        options.SetApplyPageBreaksToSheet(False)
        Convert.OfficeToPDF(pdf_doc, input_file_path, options)

        # Attempt to save the output PDF
        pdf_doc.Save(pdf_file_path, SDFDoc.e_linearized)
        logger.info(f"Converted: {input_file_path} -> {pdf_file_path}")
        list_embedded_fonts(pdf_file_path)
        return True

    except FileNotFoundError as fnfe:
        logger.error(str(fnfe), exc_info=True)
        raise

    except Exception as e:
        logger.error(f"Failed to convert {input_file_path}, Error: {e}", exc_info=True)
        raise RuntimeError(f"PDF conversion failed for {input_file_path}: {e}") from e

    finally:
        try:
            if pdf_init_done:
                logger.info("Terminating PDFTron SDK")
                pdf_init_done = False
                PDFNet.Terminate()
        except Exception as e:  # pylint: disable=W0718
            logger.error(f"Failed to terminate PDFTRON SDK instance, Error: {e}", exc_info=True)
