# SPDX-FileCopyrightText: 2024 James R. Barlow
# SPDX-License-Identifier: MPL-2.0

"""Validation coordinator for plugin options and cross-cutting concerns."""

from __future__ import annotations

import logging
import os
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from ocrmypdf._options import OcrOptions
    from ocrmypdf._plugin_manager import OcrmypdfPluginManager

log = logging.getLogger(__name__)


class ValidationCoordinator:
    """Coordinates validation across plugin models and core options."""

    def __init__(self, plugin_manager: OcrmypdfPluginManager):
        self.plugin_manager = plugin_manager

    def validate_all_options(self, options: OcrOptions) -> None:
        """Run comprehensive validation on all options.

        This runs validation in the correct order:
        1. Plugin self-validation (already done by Pydantic)
        2. Plugin context validation (requires external context)
        3. Cross-cutting validation (between plugins and core)

        Args:
            options: The options to validate
        """
        # Step 1: Plugin context validation
        self._validate_plugin_contexts(options)

        # Step 2: Cross-cutting validation
        self._validate_cross_cutting_concerns(options)

    def _validate_plugin_contexts(self, options: OcrOptions) -> None:
        """Validate plugin options that require external context."""
        # For now, we'll run the plugin validation directly since the models
        # are still being integrated. This ensures the validation warnings
        # and checks still work as expected.

        # Run Tesseract validation
        self._validate_tesseract_options(options)

        # Run Optimize validation
        self._validate_optimize_options(options)

    def _validate_tesseract_options(self, options: OcrOptions) -> None:
        """Validate Tesseract options."""
        # Check pagesegmode warning
        if options.tesseract.pagesegmode in (0, 2):
            log.warning(
                "The tesseract-pagesegmode you selected will disable OCR. "
                "This may cause processing to fail."
            )

        # Check downsample consistency
        if (
            options.tesseract.downsample_above != 32767
            and not options.tesseract.downsample_large_images
        ):
            log.warning(
                "The --tesseract-downsample-above argument will have no effect unless "
                "--tesseract-downsample-large-images is also given."
            )

        # Note: blocked languages (equ, osd) are checked earlier in
        # check_options_languages() to ensure the check runs before
        # the missing language check.

    def _validate_optimize_options(self, options: OcrOptions) -> None:
        """Validate optimization options."""
        # Check optimization consistency
        if options.optimize == 0 and any(
            [
                options.png_quality and options.png_quality > 0,
                options.jpeg_quality and options.jpeg_quality > 0,
            ]
        ):
            log.warning(
                "The arguments --png-quality and --jpeg-quality "
                "will be ignored because --optimize=0."
            )

    def _validate_cross_cutting_concerns(self, options: OcrOptions) -> None:
        """Validate cross-cutting concerns that span multiple plugins."""
        from ocrmypdf._options import ProcessingMode

        # Handle deprecated pdf_renderer values
        self._handle_deprecated_pdf_renderer(options)

        # Note: Mutual exclusivity of force_ocr/skip_text/redo_ocr is now enforced
        # by the ProcessingMode enum - only one mode can be active at a time.

        # Validate redo mode compatibility
        if options.mode == ProcessingMode.redo and (
            options.deskew or options.clean_final or options.remove_background
        ):
            raise ValueError(
                "--redo-ocr (or --mode redo) is not currently compatible with "
                "--deskew, --clean-final, and --remove-background"
            )

        # Validate output type compatibility
        output_file_display = (
            os.fsdecode(options.output_file)
            if isinstance(options.output_file, bytes)
            else str(options.output_file)
        )
        if options.output_type == 'none' and output_file_display not in (
            os.devnull,
            '-',
        ):
            raise ValueError(
                "Since you specified `--output-type none`, the output file "
                f"{output_file_display} cannot be produced. Set the output file to "
                "`-` to suppress this message."
            )

        # Validate PDF/A image compression compatibility
        if (
            options.ghostscript.pdfa_image_compression
            and options.ghostscript.pdfa_image_compression != 'auto'
            and not options.output_type.startswith('pdfa')
        ):
            log.warning(
                "--pdfa-image-compression argument only applies when "
                "--output-type is one of 'pdfa', 'pdfa-1', or 'pdfa-2'"
            )

    def _handle_deprecated_pdf_renderer(self, options: OcrOptions) -> None:
        """Handle deprecated pdf_renderer values by redirecting to fpdf2."""
        if options.pdf_renderer in ('hocr', 'hocrdebug'):
            log.info(
                "The '%s' PDF renderer has been removed. Using 'fpdf2' instead, "
                "which provides full international language support, proper RTL "
                "rendering, and improved text positioning.",
                options.pdf_renderer,
            )
            # Modify the options object to use fpdf2
            object.__setattr__(options, 'pdf_renderer', 'fpdf2')
