use pdf_syntax::object::dict::keys;
use pdf_syntax::object::{Dict, Name, Object, Stream};
use pdf_syntax::Pdf;
use std::env;

fn main() {
    let path = env::args()
        .nth(1)
        .expect("usage: debug_transparency <path>");
    let data = std::fs::read(&path).unwrap();
    let pdf = Pdf::new(data).unwrap();

    let level = pdf_compliance::detect_pdfa_level(&pdf);
    println!("Detected level: {level:?}");

    // Inline has_output_intent: check module is pub(crate), not accessible from bins.
    let has_oi = {
        let xref = pdf.xref();
        xref.get::<Dict<'_>>(xref.root_id())
            .and_then(|cat| cat.get::<pdf_syntax::object::Array<'_>>(b"OutputIntents" as &[u8]))
            .map(|intents| {
                intents.iter::<Dict<'_>>().any(|d| {
                    d.get::<Name>(b"S" as &[u8])
                        .is_some_and(|s| s.as_ref() == b"GTS_PDFA1")
                })
            })
            .unwrap_or(false)
    };
    println!("Has OutputIntent: {has_oi}");

    for (page_idx, page) in pdf.pages().iter().enumerate() {
        println!("\n=== Page {} ===", page_idx + 1);
        let page_dict = page.raw();

        // Check Group
        if let Some(group) = page_dict.get::<Dict<'_>>(b"Group" as &[u8]) {
            println!("  Has /Group dict");
            if let Some(s) = group.get::<Name>(keys::S) {
                println!("    S = {}", std::str::from_utf8(s.as_ref()).unwrap_or("?"));
            }
            if let Some(cs) = group.get::<Name>(keys::CS) {
                println!(
                    "    CS = {}",
                    std::str::from_utf8(cs.as_ref()).unwrap_or("?")
                );
            } else {
                println!("    No CS entry");
            }
        } else {
            println!("  No /Group");
        }

        // Check Resources via raw dict
        println!("  --- Raw dict Resources ---");
        if let Some(res) = page_dict.get::<Dict<'_>>(keys::RESOURCES) {
            println!("    Has /Resources (raw)");
            if let Some(gs) = res.get::<Dict<'_>>(keys::EXT_G_STATE) {
                println!("    Has /ExtGState with {} entries", gs.entries().count());
                for (name, _) in gs.entries() {
                    let nm = std::str::from_utf8(name.as_ref()).unwrap_or("?");
                    if let Some(gs_d) = gs.get::<Dict<'_>>(name.as_ref()) {
                        // Check CA/ca/BM/SMask
                        let has_ca = gs_d.get::<Object<'_>>(b"CA" as &[u8]);
                        let has_ca_lower = gs_d.get::<Object<'_>>(b"ca" as &[u8]);
                        let has_bm = gs_d.get::<Name>(keys::BM);
                        let has_smask = gs_d.get::<Object<'_>>(keys::SMASK);
                        println!(
                            "      {nm}: CA={has_ca:?} ca={has_ca_lower:?} BM={has_bm:?} SMask={}",
                            has_smask.is_some()
                        );
                    } else {
                        println!("      {nm}: could not resolve to Dict");
                    }
                }
            } else {
                println!("    No /ExtGState (raw)");
            }
        } else {
            println!("    No /Resources in raw dict");
        }

        // Check Resources via page.resources()
        println!("  --- page.resources() ---");
        let res = page.resources();
        let gs_dict = &res.ext_g_states;
        println!("    ext_g_states entries: {}", gs_dict.entries().count());
        for (name, _) in gs_dict.entries() {
            let nm = std::str::from_utf8(name.as_ref()).unwrap_or("?");
            if let Some(gs_d) = gs_dict.get::<Dict<'_>>(name.as_ref()) {
                let has_ca = gs_d.get::<Object<'_>>(b"CA" as &[u8]);
                let has_ca_lower = gs_d.get::<Object<'_>>(b"ca" as &[u8]);
                let has_bm = gs_d.get::<Name>(keys::BM);
                let has_smask = gs_d.get::<Object<'_>>(keys::SMASK);
                println!(
                    "      {nm}: CA={has_ca:?} ca={has_ca_lower:?} BM={has_bm:?} SMask={}",
                    has_smask.is_some()
                );
            } else {
                println!("      {nm}: could not resolve to Dict");
            }
        }

        // Check XObjects
        let xobj_dict = &res.x_objects;
        for (name, _) in xobj_dict.entries() {
            let nm = std::str::from_utf8(name.as_ref()).unwrap_or("?");
            if let Some(stream) = xobj_dict.get::<Stream<'_>>(name.as_ref()) {
                let dict = stream.dict();
                let subtype = dict.get::<Name>(keys::SUBTYPE);
                let st = subtype
                    .as_ref()
                    .map(|s| std::str::from_utf8(s.as_ref()).unwrap_or("?"))
                    .unwrap_or("none");
                let has_smask = dict.contains_key(keys::SMASK);
                let has_group = dict.contains_key(b"Group" as &[u8]);
                println!("    XObject {nm}: Subtype={st} SMask={has_smask} Group={has_group}");

                // If Form XObject, check its resources
                if st == "Form" {
                    if let Some(form_res) = dict.get::<Dict<'_>>(keys::RESOURCES) {
                        if let Some(gs) = form_res.get::<Dict<'_>>(keys::EXT_G_STATE) {
                            for (gname, _) in gs.entries() {
                                let gnm = std::str::from_utf8(gname.as_ref()).unwrap_or("?");
                                if let Some(gs_d) = gs.get::<Dict<'_>>(gname.as_ref()) {
                                    let ca = gs_d.get::<Object<'_>>(b"CA" as &[u8]);
                                    let ca_lower = gs_d.get::<Object<'_>>(b"ca" as &[u8]);
                                    let bm = gs_d.get::<Name>(keys::BM);
                                    let smask = gs_d.get::<Object<'_>>(keys::SMASK);
                                    println!("      Form {nm} GS {gnm}: CA={ca:?} ca={ca_lower:?} BM={bm:?} SMask={}", smask.is_some());
                                }
                            }
                        } else {
                            println!("      Form {nm}: no ExtGState in resources");
                        }
                    } else {
                        println!("      Form {nm}: no Resources");
                    }
                    // Check Group on Form XObject
                    if let Some(group) = dict.get::<Dict<'_>>(b"Group" as &[u8]) {
                        let s = group
                            .get::<Name>(keys::S)
                            .map(|s| std::str::from_utf8(s.as_ref()).unwrap_or("?").to_string())
                            .unwrap_or_default();
                        let cs = group
                            .get::<Name>(keys::CS)
                            .map(|cs| std::str::from_utf8(cs.as_ref()).unwrap_or("?").to_string())
                            .unwrap_or_default();
                        println!("      Form {nm} Group: S={s} CS={cs}");
                    }
                }
            }
        }
    }

    // Run actual validation
    if let Some(level) = level {
        let report = pdf_compliance::validate_pdfa(&pdf, level);
        println!("\n=== Compliance Report ===");
        for issue in &report.issues {
            if issue.severity == pdf_compliance::Severity::Error {
                println!(
                    "  [{}] {} ({})",
                    issue.rule,
                    issue.message,
                    issue.location.as_deref().unwrap_or("")
                );
            }
        }
    }
}
