import io
import logging
from pathlib import Path
from typing import List, Optional

import easyocr
from PIL import Image
from pypdf import PdfReader
from pypdf.errors import PdfReadError

logger = logging.getLogger(__name__)


class TextExtractor:
    """Handles text extraction and processing."""

    def __init__(self):
        """Initialize the text extractor."""
        self.reader = easyocr.Reader(["en"])

    def extract_text_from_pdf(self, pdf_path: str) -> Optional[str]:
        """Extract raw text content from a PDF file."""
        if not Path(pdf_path).exists():
            raise FileNotFoundError(f"PDF file not found: {pdf_path}")

        try:
            text_content = []
            with open(pdf_path, "rb") as file:
                reader = PdfReader(file)
                if len(reader.pages) == 0:
                    return ""

                for page in reader.pages:
                    text = page.extract_text()
                    if text.strip():
                        text_content.append(text)

            return "\n".join(text_content)
        except PdfReadError as e:
            logger.error(f"Failed to read PDF: {str(e)}")
            return ""
        except Exception as e:
            logger.error("Failed to extract text from PDF: %s", str(e))
            raise ValueError(f"Failed to extract text from PDF: {str(e)}") from e

    def extract_text_from_image(self, image: Image.Image) -> str:
        """Extract text from an image using OCR.

        Args:
            image_path: Path to the image file

        Returns:
            str: Extracted text content
        """
        try:
            # Convert PIL Image to bytes
            img_byte_arr = io.BytesIO()
            image.save(img_byte_arr, format="PNG")
            img_byte_arr = img_byte_arr.getvalue()

            # Perform OCR
            results = self.reader.readtext(img_byte_arr)

            # Extract text from results
            text = " ".join([result[1] for result in results])

            return text.strip()

        except Exception as e:
            logger.error(f"Failed to extract text from image: {str(e)}")
            raise ValueError(f"Failed to extract text from image: {str(e)}") from e

    def extract_text_from_images(self, images: List[Image.Image]) -> str:
        """Extract text from multiple images."""
        texts = []
        for image in images:
            text = self.extract_text_from_image(image)
            if text:
                texts.append(text)

        return "\n".join(texts)
