import pikepdf
import pytest

from pdftl.info.info_types import PdfInfo
from pdftl.info.set_info import set_metadata_in_pdf


@pytest.fixture
def minimal_pdf(tmp_path):
    """Creates a minimal valid PDF for testing."""
    pdf_path = tmp_path / "origin.pdf"
    with pikepdf.new() as pdf:
        pdf.add_blank_page()
        pdf.save(pdf_path)
    return pdf_path


def test_integration_id_standard_update(minimal_pdf, tmp_path):
    """
    Verify that setting a specific ID0 updates ID0 but allows ID1 to rotate.
    This confirms standard qpdf behavior: ID0 is persistent, ID1 tracks mod.
    """
    out_path = tmp_path / "updated.pdf"

    # Arbitrary hex ID (32 chars)
    target_id0_hex = "11111111111111111111111111111111"

    with pikepdf.open(minimal_pdf) as pdf:
        # Request update of ID0 only
        info = PdfInfo(ids=[target_id0_hex])
        set_metadata_in_pdf(pdf, info)
        pdf.save(out_path)

    # Verify results
    with pikepdf.open(out_path) as pdf:
        id0 = bytes(pdf.trailer.ID[0]).hex()
        id1 = bytes(pdf.trailer.ID[1]).hex()

        # ID0 should match what we set
        assert id0 == target_id0_hex

        # ID1 should usually be different (modification hash)
        # (Though extremely fast execution *might* result in collision,
        # in practice qpdf ensures they differ on update).
        assert id1 != id0


def test_integration_id_fresh_bake_reset(minimal_pdf, tmp_path):
    """
    Verify that the 'RESET' keyword triggers a 'Fresh Bake'.
    Success criteria:
    1. The resulting PDF has valid IDs (not empty).
    2. ID0 equals ID1 (indicating a fresh creation event).
    """
    out_path = tmp_path / "reset.pdf"

    with pikepdf.open(minimal_pdf) as pdf:
        # Send the RESET signal
        info = PdfInfo(ids=["RESET"])
        set_metadata_in_pdf(pdf, info)

        # Verify state in-memory before save (Should be empty bytes)
        # This confirms our safeguards prevented a crash/KeyError
        assert pdf.trailer.ID[0] == b""
        assert pdf.trailer.ID[1] == b""

        pdf.save(out_path)

    # Verify results on disk
    with pikepdf.open(out_path) as pdf:
        id0 = bytes(pdf.trailer.ID[0]).hex()
        id1 = bytes(pdf.trailer.ID[1]).hex()

        # 1. IDs should be valid (32 char hex)
        assert len(id0) == 32

        # 2. They should be identical (The "Fresh Bake" signature)
        # This proves qpdf treated it as a new file creation.
        assert id0 == id1

        # 3. They should NOT be the empty string
        assert id0 != ""


def test_integration_id1_ignored(minimal_pdf, tmp_path):
    """Verify that attempting to set ID1 is ignored and doesn't break save."""
    out_path = tmp_path / "ignore_id1.pdf"

    target_id1 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"

    with pikepdf.open(minimal_pdf) as pdf:
        original_id0 = bytes(pdf.trailer.ID[0]).hex()

        # Try to force ID1
        info = PdfInfo(ids=[None, target_id1])
        set_metadata_in_pdf(pdf, info)
        pdf.save(out_path)

    with pikepdf.open(out_path) as pdf:
        saved_id1 = bytes(pdf.trailer.ID[1]).hex()
        saved_id0 = bytes(pdf.trailer.ID[0]).hex()

        # ID0 should remain unchanged (we passed None)
        assert saved_id0 == original_id0

        # ID1 should definitely NOT match our forced input
        # (It will be a new hash generated by qpdf)
        assert saved_id1 != target_id1.lower()
