"Test importing PDF"

import datetime
import os
import re
import subprocess
import shutil
import tempfile
import img2pdf
import pytest
from gi.repository import GLib
import config
from document import Document
from loop_helpers import safe_mainloop


def test_import_multipage_pdf(rose_png, temp_pdf, temp_db):
    "Test importing PDF"
    temp_pdf.write(img2pdf.convert([rose_png, rose_png]))
    temp_pdf.flush()

    slist = Document(db=temp_db.name)

    mlp = safe_mainloop(2000)

    slist.import_files(
        paths=[temp_pdf.name],
        finished_callback=lambda response: mlp.quit(),
    )
    mlp.run()

    assert len(slist.data) == 2, "imported 2 pages"


@pytest.mark.skipif(
    shutil.which("pdfunite") is None,
    reason="Please install pdfunite (poppler utils) to enable test",
)
def test_import_multipage_pdf_with_not_enough_images(rose_png, temp_db, temp_pdf):
    "Test importing PDF"

    with (
        tempfile.NamedTemporaryFile(suffix=".pdf") as page1,
        tempfile.NamedTemporaryFile(suffix=".pdf") as page2,
    ):
        page1.write(img2pdf.convert(rose_png))
        page1.flush()
        content = b"""%PDF-1.4
1 0 obj
  << /Type /Catalog
      /Outlines 2 0 R
      /Pages 3 0 R
  >>
endobj

2 0 obj
  << /Type /Outlines
      /Count 0
  >>
endobj

3 0 obj
  << /Type /Pages
      /Kids [ 4 0 R ]
      /Count 1
  >>
endobj

4 0 obj
  << /Type /Page
      /Parent 3 0 R
      /MediaBox [ 0 0 612 792 ]
      /Contents 7 0 R
      /Resources 5 0 R
  >>
endobj

5 0 obj
  << /Font <</F1 6 0 R >> >>
endobj

6 0 obj
  << /Type /Font
      /Subtype /Type1
      /Name /F1
      /BaseFont /Courier
  >>
endobj

7 0 obj
  << /Length 62 >>
stream
  BT
    /F1 24 Tf
    100 100 Td
    ( Hello World ) Tj
  ET
endstream
endobj
xref
0 8
0000000000 65535 f 
0000000009 00000 n 
0000000091 00000 n 
0000000148 00000 n 
0000000224 00000 n 
0000000359 00000 n 
0000000404 00000 n 
0000000505 00000 n 
trailer
<</Size 8/Root 1 0 R>> 
startxref
618
%%EOF
"""
        page2.write(content)
        page2.flush()
        subprocess.run(["pdfunite", page1.name, page2.name, temp_pdf.name], check=True)

    slist = Document(db=temp_db.name)

    mlp = safe_mainloop(2000)

    asserts = 0

    def error_cb(response):
        nonlocal asserts
        assert re.search(
            r"one image per page", response.status
        ), "one image per page warning"
        asserts += 1
        mlp.quit()

    slist.import_files(
        paths=[temp_pdf.name],
        error_callback=error_cb,
        finished_callback=lambda response: mlp.quit(),
    )
    mlp.run()

    assert asserts == 1, "all callbacks run"
    assert len(slist.data) == 1, "imported 1 pages"


def test_import_pdf_bw(temp_png, temp_pdf, temp_db, get_page_sync):
    "Test importing PDF"

    options = [
        config.CONVERT_COMMAND,
        "-density",
        "300",
        "label:The quick brown fox",
        "-alpha",
        "Off",
        "-depth",
        "1",
        "-colorspace",
        "Gray",
        "-type",
        "Bilevel",
        "-family",
        "DejaVu Sans",
        "-pointsize",
        "12",
        temp_png.name,
    ]
    subprocess.run(options, check=True)
    temp_pdf.write(img2pdf.convert(temp_png))
    temp_pdf.flush()

    slist = Document(db=temp_db.name)

    mlp = safe_mainloop(2000)

    slist.import_files(
        paths=[temp_pdf.name],
        finished_callback=lambda response: mlp.quit(),
    )
    mlp.run()

    assert (
        get_page_sync(slist.thread, id=1).image_object.mode == "1"
    ), "BW PDF imported correctly"


def test_import_pdf_with_error(rose_png, temp_pdf):
    "Test importing PDF"
    temp_pdf.write(img2pdf.convert(rose_png))
    temp_pdf.flush()

    with tempfile.TemporaryDirectory() as dirname:
        slist = Document(dir=dirname)

        mlp = safe_mainloop()

        asserts = 0

        def queued_cb(response):
            nonlocal asserts
            if asserts == 0:
                asserts += 1

                # inject error during import file
                os.chmod(dirname, 0o500)  # no write access

        def error_cb(*args):
            nonlocal asserts
            message = args[-1] if len(args) > 1 else args[0].status
            assert message, "error_cb"
            asserts += 1

            # inject error during import file
            os.chmod(dirname, 0o700)  # allow write access

        slist.import_files(
            paths=[temp_pdf.name],
            queued_callback=queued_cb,
            error_callback=error_cb,
            finished_callback=lambda response: mlp.quit(),
        )
        mlp.run()

        assert asserts == 2, "all callbacks run"


@pytest.mark.skipif(
    shutil.which("qpdf") is None, reason="Please install qpdf to enable test"
)
def test_import_encrypted_pdf(rose_png, temp_db, temp_pdf, clean_up_files):
    "Test importing PDF"

    temp_pdf.write(img2pdf.convert(rose_png))
    temp_pdf.flush()
    subprocess.run(
        [
            "qpdf",
            "--encrypt",
            "--owner-password=s3cr3t",
            "--user-password=s3cr3t",
            "--bits=256",
            "--allow-insecure",
            "--",
            temp_pdf.name,
            "output.pdf",
        ],
        check=True,
    )

    slist = Document(db=temp_db.name)

    mlp = safe_mainloop(2000)

    asserts = 0

    def password_cb(path):
        nonlocal asserts
        assert path == "output.pdf"
        asserts += 1
        return "s3cr3t"

    slist.import_files(
        paths=["output.pdf"],
        password_callback=password_cb,
        finished_callback=lambda response: mlp.quit(),
    )
    mlp.run()

    assert asserts == 1, "callbacks all run"
    assert len(slist.data) == 1, "imported 1 page"

    #########################

    clean_up_files(["output.pdf"])


def test_import_pdf_with_metadata(rose_png, temp_pdf, temp_db):
    "Test importing PDF"
    temp_pdf.write(
        img2pdf.convert(
            rose_png,
            author="Authör",
            title="Title",
            subject="Sübject",
            keywords=["Keywörds"],
            creationdate=datetime.datetime(
                2018, 12, 31, 12, 0, tzinfo=datetime.timezone.utc
            ),
        )
    )
    temp_pdf.flush()

    slist = Document(db=temp_db.name)

    mlp = safe_mainloop()

    asserts = 0

    def metadata_cb(response):
        assert response["datetime"] == datetime.datetime(
            2018, 12, 31, 12, 0, tzinfo=datetime.timezone.utc
        ), "datetime"
        assert response["author"] == "Authör", "author"
        assert response["subject"] == "Sübject", "subject"
        assert response["keywords"] == "Keywörds", "keywords"
        assert response["title"] == "Title", "title"
        nonlocal asserts
        asserts += 1

    slist.import_files(
        paths=[temp_pdf.name],
        metadata_callback=metadata_cb,
        finished_callback=lambda response: mlp.quit(),
    )
    mlp.run()

    assert asserts == 1, "callbacks all run"


def test_import_pdf_with_placeholder_title(rose_png, temp_pdf, temp_db):
    "Test importing PDF with a placeholder title"
    temp_pdf.write(img2pdf.convert(rose_png, title="Untitled"))
    temp_pdf.flush()

    slist = Document(db=temp_db.name)

    mlp = safe_mainloop()

    asserts = 0

    def metadata_cb(response):
        assert "title" not in response, "placeholder title not imported"
        nonlocal asserts
        asserts += 1

    slist.import_files(
        paths=[temp_pdf.name],
        metadata_callback=metadata_cb,
        finished_callback=lambda response: mlp.quit(),
    )
    mlp.run()

    assert asserts == 1, "callbacks all run"
