import json

from django.test import TestCase
from django.test import override_settings

from documents.tests.utils import DirectoriesMixin
from documents.tests.utils import FileSystemAssertsMixin
from paperless.models import ApplicationConfiguration
from paperless.models import CleanChoices
from paperless.models import ColorConvertChoices
from paperless.models import ModeChoices
from paperless.models import OutputTypeChoices
from paperless.parsers.tesseract import RasterisedDocumentParser


class TestParserSettingsFromDb(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
    @classmethod
    def setUpTestData(cls) -> None:
        super().setUpTestData()
        ApplicationConfiguration.objects.get_or_create()

    @staticmethod
    def get_params():
        """
        Helper to get just the OCRMyPDF parameters from the parser
        """
        return RasterisedDocumentParser(None).construct_ocrmypdf_parameters(
            input_file="input.pdf",
            output_file="output.pdf",
            sidecar_file="sidecar.txt",
            mime_type="application/pdf",
            safe_fallback=False,
        )

    def test_db_settings_ocr_pages(self) -> None:
        """
        GIVEN:
            - Django settings defines different value for OCR_PAGES than
              configuration object
        WHEN:
            - OCR parameters are constructed
        THEN:
            - Configuration from database is utilized
        """
        with override_settings(OCR_PAGES=10):
            instance = ApplicationConfiguration.objects.all().first()
            assert instance is not None
            instance.pages = 5
            instance.save()

            params = self.get_params()
        self.assertEqual(params["pages"], "1-5")

    def test_db_settings_ocr_language(self) -> None:
        """
        GIVEN:
            - Django settings defines different value for OCR_LANGUAGE than
              configuration object
        WHEN:
            - OCR parameters are constructed
        THEN:
            - Configuration from database is utilized
        """
        with override_settings(OCR_LANGUAGE="eng+deu"):
            instance = ApplicationConfiguration.objects.all().first()
            assert instance is not None
            instance.language = "fra+ita"
            instance.save()

            params = self.get_params()
        self.assertEqual(params["language"], "fra+ita")

    def test_db_settings_ocr_output_type(self) -> None:
        """
        GIVEN:
            - Django settings defines different value for OCR_OUTPUT_TYPE than
              configuration object
        WHEN:
            - OCR parameters are constructed
        THEN:
            - Configuration from database is utilized
        """
        with override_settings(OCR_OUTPUT_TYPE="pdfa-3"):
            instance = ApplicationConfiguration.objects.all().first()
            assert instance is not None
            instance.output_type = OutputTypeChoices.PDF_A
            instance.save()

            params = self.get_params()
        self.assertEqual(params["output_type"], "pdfa")

    def test_db_settings_ocr_mode(self) -> None:
        """
        GIVEN:
            - Django settings defines different value for OCR_MODE than
              configuration object
        WHEN:
            - OCR parameters are constructed
        THEN:
            - Configuration from database is utilized (AUTO mode with skip_text=True
              triggers skip_text; AUTO mode alone does not add any extra flag)
        """
        # AUTO mode with skip_text=True explicitly passed: skip_text is set
        with override_settings(OCR_MODE="redo"):
            instance = ApplicationConfiguration.objects.all().first()
            assert instance is not None
            instance.mode = ModeChoices.AUTO
            instance.save()

            params = RasterisedDocumentParser(None).construct_ocrmypdf_parameters(
                input_file="input.pdf",
                output_file="output.pdf",
                sidecar_file="sidecar.txt",
                mime_type="application/pdf",
                safe_fallback=False,
                skip_text=True,
            )
        self.assertTrue(params["skip_text"])
        self.assertNotIn("redo_ocr", params)
        self.assertNotIn("force_ocr", params)

        # AUTO mode alone (no skip_text): no extra OCR flag is set
        with override_settings(OCR_MODE="redo"):
            instance = ApplicationConfiguration.objects.all().first()
            assert instance is not None
            instance.mode = ModeChoices.AUTO
            instance.save()

            params = self.get_params()
        self.assertNotIn("skip_text", params)
        self.assertNotIn("redo_ocr", params)
        self.assertNotIn("force_ocr", params)

    def test_db_settings_ocr_clean(self) -> None:
        """
        GIVEN:
            - Django settings defines different value for OCR_CLEAN than
              configuration object
        WHEN:
            - OCR parameters are constructed
        THEN:
            - Configuration from database is utilized
        """
        with override_settings(OCR_CLEAN="clean-final"):
            instance = ApplicationConfiguration.objects.all().first()
            assert instance is not None
            instance.unpaper_clean = CleanChoices.CLEAN
            instance.save()

            params = self.get_params()
        self.assertTrue(params["clean"])
        self.assertNotIn("clean_final", params)

        with override_settings(OCR_CLEAN="clean-final"):
            instance = ApplicationConfiguration.objects.all().first()
            assert instance is not None
            instance.unpaper_clean = CleanChoices.FINAL
            instance.save()

            params = self.get_params()
        self.assertTrue(params["clean_final"])
        self.assertNotIn("clean", params)

    def test_db_settings_ocr_deskew(self) -> None:
        """
        GIVEN:
            - Django settings defines different value for OCR_DESKEW than
              configuration object
        WHEN:
            - OCR parameters are constructed
        THEN:
            - Configuration from database is utilized
        """
        with override_settings(OCR_DESKEW=False):
            instance = ApplicationConfiguration.objects.all().first()
            assert instance is not None
            instance.deskew = True
            instance.save()

            params = self.get_params()
        self.assertTrue(params["deskew"])

    def test_db_settings_ocr_rotate(self) -> None:
        """
        GIVEN:
            - Django settings defines different value for OCR_ROTATE_PAGES
              and OCR_ROTATE_PAGES_THRESHOLD than configuration object
        WHEN:
            - OCR parameters are constructed
        THEN:
            - Configuration from database is utilized
        """
        with override_settings(OCR_ROTATE_PAGES=False, OCR_ROTATE_PAGES_THRESHOLD=30.0):
            instance = ApplicationConfiguration.objects.all().first()
            assert instance is not None
            assert instance is not None
            instance.rotate_pages = True
            instance.rotate_pages_threshold = 15.0
            instance.save()

            params = self.get_params()
        self.assertTrue(params["rotate_pages"])
        self.assertAlmostEqual(params["rotate_pages_threshold"], 15.0)

    def test_db_settings_ocr_max_pixels(self) -> None:
        """
        GIVEN:
            - Django settings defines different value for OCR_MAX_IMAGE_PIXELS than
              configuration object
        WHEN:
            - OCR parameters are constructed
        THEN:
            - Configuration from database is utilized
        """
        with override_settings(OCR_MAX_IMAGE_PIXELS=2_000_000.0):
            instance = ApplicationConfiguration.objects.all().first()
            assert instance is not None
            instance.max_image_pixels = 1_000_000.0
            instance.save()

            params = self.get_params()
        self.assertAlmostEqual(params["max_image_mpixels"], 1.0)

    def test_db_settings_ocr_color_convert(self) -> None:
        """
        GIVEN:
            - Django settings defines different value for OCR_COLOR_CONVERSION_STRATEGY than
              configuration object
        WHEN:
            - OCR parameters are constructed
        THEN:
            - Configuration from database is utilized
        """
        with override_settings(OCR_COLOR_CONVERSION_STRATEGY="LeaveColorUnchanged"):
            instance = ApplicationConfiguration.objects.all().first()
            assert instance is not None
            instance.color_conversion_strategy = ColorConvertChoices.INDEPENDENT
            instance.save()

            params = self.get_params()
        self.assertEqual(
            params["color_conversion_strategy"],
            "UseDeviceIndependentColor",
        )

    def test_ocr_user_args(self) -> None:
        """
        GIVEN:
            - Django settings defines different value for OCR_USER_ARGS than
              configuration object
        WHEN:
            - OCR parameters are constructed
        THEN:
            - Configuration from database is utilized
        """
        with override_settings(
            OCR_USER_ARGS=json.dumps({"continue_on_soft_render_error": True}),
        ):
            instance = ApplicationConfiguration.objects.all().first()
            assert instance is not None
            instance.user_args = {"unpaper_args": "--pre-rotate 90"}
            instance.save()

            params = self.get_params()

        self.assertIn("unpaper_args", params)
        self.assertEqual(
            params["unpaper_args"],
            "--pre-rotate 90",
        )
