"""
Validation test — exercises the S3/MinIO integration logic against a mock S3.
Verifies: upload, download, presigned URLs, metadata, MIME validation.
"""
import io
import boto3
from moto import mock_aws
import hashlib

BUCKET = "sangkien-attachments"

ALLOWED = {"application/pdf", "image/png", "image/jpeg"}


def build_key(app_id, filename):
    from datetime import datetime, timezone
    import uuid
    now = datetime.now(tz=timezone.utc)
    unique = uuid.uuid4().hex[:16]
    safe = filename.replace("/", "_").replace(" ", "_")
    return f"{app_id}/{now:%Y}/{now:%m}/{unique}-{safe}"


def upload(s3, key, data, mime_type, metadata):
    if mime_type not in ALLOWED:
        raise ValueError(f"MIME not allowed: {mime_type}")
    sha = hashlib.sha256(data).hexdigest()
    s3.put_object(
        Bucket=BUCKET, Key=key, Body=data,
        ContentType=mime_type, Metadata={"sha256": sha, **metadata},
        ServerSideEncryption="AES256",
    )
    return {"key": key, "size": len(data), "sha256": sha}


@mock_aws
def test_full_flow():
    s3 = boto3.client("s3", region_name="us-east-1")
    s3.create_bucket(Bucket=BUCKET)

    # 1. Upload a fake PDF
    fake_pdf = b"%PDF-1.4\n%fake content for testing\n" * 100
    key = build_key(app_id=42, filename="flowchart sáng kiến.pdf")
    result = upload(s3, key, fake_pdf, "application/pdf",
                    {"uploaded_by": "7", "app_id": "42"})
    print(f"✓ Uploaded: {result['key']}")
    print(f"  size={result['size']} sha256={result['sha256'][:16]}...")

    # 2. Head object — verify metadata survived
    head = s3.head_object(Bucket=BUCKET, Key=key)
    assert head["ContentType"] == "application/pdf"
    assert head["Metadata"]["uploaded_by"] == "7"
    assert head["Metadata"]["sha256"] == result["sha256"]
    print(f"✓ Metadata preserved: uploaded_by={head['Metadata']['uploaded_by']}")

    # 3. Generate pre-signed download URL
    download_url = s3.generate_presigned_url(
        "get_object",
        Params={"Bucket": BUCKET, "Key": key,
                "ResponseContentDisposition": 'attachment; filename="flowchart.pdf"'},
        ExpiresIn=900,
    )
    assert "Signature=" in download_url and "Expires=" in download_url
    print(f"✓ Signed download URL generated (TTL=900s)")

    # 4. Generate pre-signed upload URL (for large-file flow)
    upload_url = s3.generate_presigned_url(
        "put_object",
        Params={"Bucket": BUCKET, "Key": "42/2025/10/new-large-file.pdf",
                "ContentType": "application/pdf"},
        ExpiresIn=900,
    )
    assert "Signature=" in upload_url
    print(f"✓ Signed upload URL generated")

    # 5. Download and verify bytes match
    obj = s3.get_object(Bucket=BUCKET, Key=key)
    got = obj["Body"].read()
    assert got == fake_pdf
    assert hashlib.sha256(got).hexdigest() == result["sha256"]
    print(f"✓ Download: {len(got)} bytes, hash matches")

    # 6. MIME validation rejects bad types
    try:
        upload(s3, "bad.exe", b"MZ\x90", "application/x-msdownload", {})
        assert False, "Should have rejected .exe"
    except ValueError as e:
        print(f"✓ MIME validation blocked: {e}")

    # 7. Delete creates a delete marker (versioning), object recoverable
    s3.put_bucket_versioning(
        Bucket=BUCKET,
        VersioningConfiguration={"Status": "Enabled"},
    )
    # Re-upload with versioning on, then delete
    key2 = "42/2025/10/versioned.pdf"
    s3.put_object(Bucket=BUCKET, Key=key2, Body=b"v1", ContentType="application/pdf")
    s3.delete_object(Bucket=BUCKET, Key=key2)
    versions = s3.list_object_versions(Bucket=BUCKET, Prefix=key2)
    has_delete_marker = any(dm for dm in versions.get("DeleteMarkers", []))
    has_version = any(v for v in versions.get("Versions", []))
    assert has_delete_marker and has_version
    print(f"✓ Versioning: delete marker present, previous version recoverable")

    # 8. List objects under a prefix (application-scoped listing)
    resp = s3.list_objects_v2(Bucket=BUCKET, Prefix="42/")
    keys = [o["Key"] for o in resp.get("Contents", [])]
    print(f"✓ Listed {len(keys)} objects under prefix 42/")

    print("\n✅ All checks passed")


@mock_aws
def test_research_evidence_pdf_upload_metadata():
    """Parity check: applicant research PDF uses same bucket + PDF MIME as attachment pipeline."""
    s3 = boto3.client("s3", region_name="us-east-1")
    s3.create_bucket(Bucket=BUCKET)
    pdf = b"%PDF-1.4 research evidence fixture\n"
    key = build_key(app_id=99, filename="minh-chung-nhom-2.1.4.pdf")
    meta = {"uploaded_by": "1", "app_id": "99", "case_code": "CASE-MERIT", "role": "research_evidence"}
    result = upload(s3, key, pdf, "application/pdf", meta)
    head = s3.head_object(Bucket=BUCKET, Key=key)
    assert head["Metadata"]["role"] == "research_evidence"
    assert head["Metadata"]["case_code"] == "CASE-MERIT"
    assert head["ContentType"] == "application/pdf"
    assert result["sha256"] == hashlib.sha256(pdf).hexdigest()


if __name__ == "__main__":
    test_full_flow()
    test_research_evidence_pdf_upload_metadata()
