use pixstrip_core::operations::MetadataConfig;
use pixstrip_core::operations::metadata::strip_metadata;
use std::path::Path;

fn create_test_jpeg(path: &Path) {
    let img = image::RgbImage::from_fn(100, 80, |x, y| {
        image::Rgb([(x % 256) as u8, (y % 256) as u8, 128])
    });
    img.save_with_format(path, image::ImageFormat::Jpeg).unwrap();
}

#[test]
fn strip_all_metadata_produces_file() {
    let dir = tempfile::tempdir().unwrap();
    let input = dir.path().join("test.jpg");
    let output = dir.path().join("stripped.jpg");
    create_test_jpeg(&input);

    strip_metadata(&input, &output, &MetadataConfig::StripAll).unwrap();
    assert!(output.exists());
    assert!(std::fs::metadata(&output).unwrap().len() > 0);
}

#[test]
fn keep_all_metadata_copies_file() {
    let dir = tempfile::tempdir().unwrap();
    let input = dir.path().join("test.jpg");
    let output = dir.path().join("kept.jpg");
    create_test_jpeg(&input);

    strip_metadata(&input, &output, &MetadataConfig::KeepAll).unwrap();
    assert!(output.exists());
}

#[test]
fn privacy_mode_strips_gps() {
    let dir = tempfile::tempdir().unwrap();
    let input = dir.path().join("test.jpg");
    let output = dir.path().join("privacy.jpg");
    create_test_jpeg(&input);

    strip_metadata(&input, &output, &MetadataConfig::Privacy).unwrap();
    assert!(output.exists());
}

fn create_test_png(path: &Path) {
    let img = image::RgbaImage::from_fn(100, 80, |x, y| {
        image::Rgba([(x % 256) as u8, (y % 256) as u8, 128, 255])
    });
    img.save_with_format(path, image::ImageFormat::Png).unwrap();
}

#[test]
fn strip_png_metadata_produces_valid_png() {
    let dir = tempfile::tempdir().unwrap();
    let input = dir.path().join("test.png");
    let output = dir.path().join("stripped.png");
    create_test_png(&input);

    strip_metadata(&input, &output, &MetadataConfig::StripAll).unwrap();
    assert!(output.exists());
    // Output must be a valid PNG that can be opened
    let img = image::open(&output).unwrap();
    assert_eq!(img.width(), 100);
    assert_eq!(img.height(), 80);
}

#[test]
fn strip_png_removes_text_chunks() {
    let dir = tempfile::tempdir().unwrap();
    let input = dir.path().join("test.png");
    let output = dir.path().join("stripped.png");
    create_test_png(&input);

    strip_metadata(&input, &output, &MetadataConfig::StripAll).unwrap();
    // Read output and verify no tEXt chunks remain
    let data = std::fs::read(&output).unwrap();
    let mut pos = 8; // skip PNG signature
    while pos + 12 <= data.len() {
        let chunk_len = u32::from_be_bytes([data[pos], data[pos+1], data[pos+2], data[pos+3]]) as usize;
        let chunk_type = &data[pos+4..pos+8];
        assert_ne!(chunk_type, b"tEXt", "tEXt chunk should be stripped");
        assert_ne!(chunk_type, b"iTXt", "iTXt chunk should be stripped");
        assert_ne!(chunk_type, b"zTXt", "zTXt chunk should be stripped");
        pos += 12 + chunk_len;
    }
}

#[test]
fn strip_png_output_smaller_or_equal() {
    let dir = tempfile::tempdir().unwrap();
    let input = dir.path().join("test.png");
    let output = dir.path().join("stripped.png");
    create_test_png(&input);

    let input_size = std::fs::metadata(&input).unwrap().len();
    strip_metadata(&input, &output, &MetadataConfig::StripAll).unwrap();
    let output_size = std::fs::metadata(&output).unwrap().len();
    assert!(output_size <= input_size);
}

#[test]
fn strip_jpeg_removes_app1_exif() {
    let dir = tempfile::tempdir().unwrap();
    let input = dir.path().join("test.jpg");
    let output = dir.path().join("stripped.jpg");
    create_test_jpeg(&input);

    strip_metadata(&input, &output, &MetadataConfig::StripAll).unwrap();
    // Verify no APP1 (0xFFE1) markers remain
    let data = std::fs::read(&output).unwrap();
    let mut i = 2; // skip SOI
    while i + 1 < data.len() {
        if data[i] != 0xFF { break; }
        let marker = data[i + 1];
        if marker == 0xDA { break; } // SOS - rest is image data
        assert_ne!(marker, 0xE1, "APP1/EXIF marker should be stripped");
        if i + 3 < data.len() {
            let len = ((data[i + 2] as usize) << 8) | (data[i + 3] as usize);
            i += 2 + len;
        } else {
            break;
        }
    }
}
