use std::fs;
use tempfile::tempdir;

#[test]
fn test_md013_reflow_via_cli() {
    let dir = tempdir().unwrap();
    let file_path = dir.path().join("test.md");

    // Create test file with long lines
    let content = "This is a very long line that definitely exceeds the default eighty character limit and needs to be wrapped properly by the reflow algorithm.

## Heading

- This is a very long list item that needs to be wrapped properly with correct indentation
- Another long list item that should also be wrapped with the proper continuation indentation

Regular paragraph with **bold text** and *italic text* and `inline code` that needs wrapping.";

    fs::write(&file_path, content).unwrap();

    // Create config file enabling reflow
    // TODO: Fix backwards compatibility - enable-reflow should also work
    let config_path = dir.path().join(".rumdl.toml");
    let config_content = r#"
[MD013]
line-length = 40
reflow = true
"#;
    fs::write(&config_path, config_content).unwrap();

    // First check what violations exist (for debugging if needed)
    let _check_output = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl check");

    // Run rumdl with fix
    let output = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--fix")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl");

    // With --fix, rumdl returns exit code 1 if violations were found (even if fixed)
    // Exit code 2 indicates an actual error
    let exit_code = output.status.code().unwrap_or(-1);
    if exit_code == 2 {
        eprintln!("stdout: {}", String::from_utf8_lossy(&output.stdout));
        eprintln!("stderr: {}", String::from_utf8_lossy(&output.stderr));
        panic!("rumdl failed with error exit code 2");
    }

    // Verify fixes were applied
    let stdout = String::from_utf8_lossy(&output.stdout);
    assert!(
        stdout.contains("Fixed:") || stdout.contains("fixed"),
        "Expected fixes to be applied, but got: {stdout}"
    );

    // Read the fixed content
    let fixed_content = fs::read_to_string(&file_path).unwrap();

    // Verify reflow worked (lines should be reasonably short)
    for line in fixed_content.lines() {
        if !line.starts_with('#') && !line.trim().is_empty() && !line.contains('`') {
            // Be realistic about what reflow can achieve:
            // - List items need space for markers
            // - Continuation lines need indentation
            // - Words can't be broken
            let is_indented = line.starts_with(' ');
            let reasonable_limit = if is_indented { 50 } else { 45 };

            assert!(
                line.chars().count() <= reasonable_limit,
                "Line seems too long after reflow: {} ({} chars)",
                line,
                line.chars().count()
            );
        }
    }

    // Verify markdown elements are preserved
    assert!(fixed_content.contains("**bold text**"));
    assert!(fixed_content.contains("*italic text*"));
    assert!(fixed_content.contains("`inline code`"));

    // Verify list structure is preserved
    assert!(fixed_content.contains("- This"));
    assert!(fixed_content.contains("- Another"));
}

#[test]
fn test_md013_reflow_disabled_by_default() {
    let dir = tempdir().unwrap();
    let file_path = dir.path().join("test.md");

    // Create test file with long line that has no trailing whitespace
    let content = "This is a very long line that definitely exceeds the default eighty character limit but has no trailing whitespace";
    fs::write(&file_path, content).unwrap();

    // Run rumdl with fix (no config, so reflow should be disabled)
    let output = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--no-config")
        .arg("--fix")
        .arg(&file_path)
        .output()
        .expect("Failed to execute rumdl");

    // Should complete without error (exit code 0 or 1, not 2)
    let exit_code = output.status.code().unwrap_or(-1);
    assert!(exit_code == 0 || exit_code == 1, "Unexpected exit code: {exit_code}");

    // The long line should not be wrapped (reflow disabled by default)
    let fixed_content = fs::read_to_string(&file_path).unwrap();

    // Check that the long line is still present (not reflowed)
    assert!(
        fixed_content.contains(content),
        "Expected the long line to remain unchanged, but it was modified"
    );
}

#[test]
fn test_md013_reflow_complex_document() {
    let dir = tempdir().unwrap();
    let file_path = dir.path().join("complex.md");

    let content = r#"# Complex Document Test

This is a very long introduction paragraph that contains multiple sentences and definitely exceeds the line length limit. It should be wrapped properly while preserving all the markdown formatting.

## Code Examples

Here's some code that should not be wrapped:

```python
def very_long_function_name_with_many_parameters(param1, param2, param3, param4):
    return "This is a very long string that should not be wrapped even if it exceeds the limit"
```

## Lists and Quotes

1. First numbered item that is very long and needs to be wrapped correctly with proper indentation
2. Second item that is also quite long and requires proper wrapping to fit within limits

> This is a blockquote that contains a very long line that needs to be wrapped properly while preserving the blockquote marker on each line.

## Tables

| Column 1 | Column 2 with very long header that exceeds limit |
|----------|---------------------------------------------------|
| Data 1   | Very long cell content that should not be wrapped |

## Links and References

For more information, see [our documentation](https://example.com/very/long/url/that/should/not/break) and the [reference guide][ref].

[ref]: https://example.com/another/very/long/url/for/reference
"#;

    fs::write(&file_path, content).unwrap();

    // Create config with specific settings
    // TODO: Fix backwards compatibility - enable-reflow should also work
    let config_path = dir.path().join(".rumdl.toml");
    let config_content = r#"
[MD013]
line-length = 50
reflow = true
code-blocks = true
tables = true
"#;
    fs::write(&config_path, config_content).unwrap();

    // Run rumdl with fix
    let output = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--fix")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl");

    let exit_code = output.status.code().unwrap_or(-1);
    assert!(exit_code == 0 || exit_code == 1, "Unexpected exit code: {exit_code}");

    let fixed_content = fs::read_to_string(&file_path).unwrap();

    // Verify structure is preserved
    assert!(fixed_content.contains("# Complex Document Test"));
    assert!(fixed_content.contains("```python"));
    assert!(fixed_content.contains("def very_long_function_name_with_many_parameters"));
    assert!(fixed_content.contains("|----------|"));
    assert!(fixed_content.contains("[ref]: https://example.com/another/very/long/url/for/reference"));

    // Verify proper wrapping of regular content
    let lines: Vec<&str> = fixed_content.lines().collect();
    let mut in_code = false;
    for line in &lines {
        if line.starts_with("```") {
            in_code = !in_code;
            continue;
        }

        // Skip special lines
        if !in_code
            && !line.starts_with('#')
            && !line.starts_with('|')
            && !line.starts_with('[')
            && !line.trim().is_empty()
        {
            // Allow slightly more for list items and lines with URLs
            let is_list_item = line.trim_start().starts_with("- ")
                || line.trim_start().starts_with("* ")
                || line.trim_start().chars().next().is_some_and(|c| c.is_numeric());
            let contains_url = line.contains("http://") || line.contains("https://");
            let limit = if is_list_item || contains_url { 80 } else { 50 };

            assert!(
                line.chars().count() <= limit,
                "Line exceeds limit: {} ({} > {})",
                line,
                line.chars().count(),
                limit
            );
        }
    }
}

#[test]
fn test_md013_reflow_preserves_exact_content() {
    let dir = tempdir().unwrap();
    let file_path = dir.path().join("preserve.md");

    // Content with various markdown elements
    let content = "This paragraph has **bold text** and *italic text* and [a link](https://example.com) and `inline code` that should all be preserved exactly during the reflow process.";

    fs::write(&file_path, content).unwrap();

    let config_path = dir.path().join(".rumdl.toml");
    let config_content = r#"
[MD013]
line-length = 30
enable-reflow = true
"#;
    fs::write(&config_path, config_content).unwrap();

    let output = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--fix")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl");

    let exit_code = output.status.code().unwrap_or(-1);
    assert!(exit_code == 0 || exit_code == 1, "Unexpected exit code: {exit_code}");

    let fixed_content = fs::read_to_string(&file_path).unwrap();

    // Extract all words and markdown elements to verify nothing was lost
    let original_elements = vec![
        "**bold text**",
        "*italic text*",
        "[a link](https://example.com)",
        "`inline code`",
    ];

    for element in &original_elements {
        assert!(
            fixed_content.contains(element),
            "Missing element: {element} in:\n{fixed_content}"
        );
    }

    // Verify all original words are preserved
    let original_words: Vec<&str> = content.split_whitespace().collect();
    for word in &original_words {
        assert!(fixed_content.contains(word), "Missing word '{word}' in fixed content");
    }
}

/// Issue #338: Snippet delimiters in list items should not be reflowed
#[test]
fn test_md013_issue_338_snippets_in_list_items() {
    use rumdl_lib::config::{Config, MarkdownFlavor, RuleConfig};
    use rumdl_lib::rules;

    // Test that snippet delimiters are preserved in list items
    let content = r#"# Test

- Some content:
  -8<-
  https://raw.githubusercontent.com/example/file.md
  -8<-

More text.
"#;

    let mut config = Config::default();
    let mut rule_config = RuleConfig::default();
    rule_config
        .values
        .insert("reflow".to_string(), toml::Value::Boolean(true));
    config.rules.insert("MD013".to_string(), rule_config);

    let all_rules = rules::all_rules(&config);
    let md013_rules: Vec<_> = all_rules.into_iter().filter(|r| r.name() == "MD013").collect();

    let result = rumdl_lib::lint(content, &md013_rules, false, MarkdownFlavor::Standard, None, None).unwrap();

    // Should have no warnings since content is already properly formatted
    // The snippet delimiters should be recognized and preserved
    assert_eq!(
        result.len(),
        0,
        "Issue #338: Snippet delimiters should be preserved. Found warnings: {:?}",
        result
            .iter()
            .map(|w| format!("Line {}: {}", w.line, w.message))
            .collect::<Vec<_>>()
    );
}

/// Issue #338: Snippet delimiters should stay on their own lines after reflow via CLI
#[test]
fn test_md013_issue_338_snippets_preserved_after_reflow_via_cli() {
    let dir = tempdir().unwrap();
    let file_path = dir.path().join("test_snippets.md");

    // Test that snippet delimiters are preserved when surrounding content is reflowed
    let content = r#"# Test

- Some content that is long enough to trigger reflow and also has a snippet block inside:
  -8<-
  https://raw.githubusercontent.com/example/file.md
  -8<-

More text.
"#;
    fs::write(&file_path, content).unwrap();

    // Create config enabling reflow
    let config_path = dir.path().join(".rumdl.toml");
    let config_content = r#"
[MD013]
reflow = true
"#;
    fs::write(&config_path, config_content).unwrap();

    // Run rumdl fmt to apply fix
    let output = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("fmt")
        .arg("--no-cache")
        .arg("-e")
        .arg("MD013")
        .arg("--config")
        .arg(&config_path)
        .arg(&file_path)
        .output()
        .expect("Failed to execute rumdl");

    // Read the fixed content
    let fixed = fs::read_to_string(&file_path).unwrap();

    // Verify snippet delimiters are preserved on their own lines
    assert!(
        fixed.contains("  -8<-\n  https://"),
        "Snippet delimiter should be on its own line, followed by URL. Got:\n{fixed}",
    );
    assert!(
        fixed.lines().filter(|l| l.trim() == "-8<-").count() == 2,
        "Both snippet delimiters should be preserved. Got:\n{fixed}",
    );

    // Verify the URL is still there
    assert!(
        fixed.contains("https://raw.githubusercontent.com/example/file.md"),
        "URL should be preserved. Got:\n{fixed}",
    );

    // Verify success
    assert!(
        output.status.success() || String::from_utf8_lossy(&output.stdout).contains("Fixed"),
        "Command should succeed or fix. Stderr: {}",
        String::from_utf8_lossy(&output.stderr)
    );
}

#[test]
fn test_md013_semantic_line_breaks_via_cli() {
    let dir = tempdir().unwrap();
    let file_path = dir.path().join("test.md");

    let content = "All human beings are born free and equal in dignity and rights. They are endowed with reason and conscience and should act towards one another in a spirit of brotherhood.\n";
    fs::write(&file_path, content).unwrap();

    let config_path = dir.path().join(".rumdl.toml");
    let config_content = r#"
[MD013]
line-length = 80
reflow = true
reflow-mode = "semantic-line-breaks"
"#;
    fs::write(&config_path, config_content).unwrap();

    // Run fix
    let _output = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--fix")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl");

    let fixed = fs::read_to_string(&file_path).unwrap();

    // Should have sentence breaks
    assert!(
        fixed.contains("rights.\n"),
        "Should break at sentence boundary: {fixed:?}"
    );

    // Each line should respect the 80-char limit (or be a single word)
    for line in fixed.lines() {
        if !line.is_empty() && line.contains(' ') {
            assert!(
                line.len() <= 85, // Allow small overshoot for edge cases
                "Line should be approximately within limit: {line:?} (len={})",
                line.len()
            );
        }
    }
}

#[test]
fn test_md013_semantic_line_breaks_idempotent() {
    let dir = tempdir().unwrap();
    let file_path = dir.path().join("test.md");

    let content = "First sentence is here. Second sentence is also present. Third sentence completes the paragraph.\n";
    fs::write(&file_path, content).unwrap();

    let config_path = dir.path().join(".rumdl.toml");
    let config_content = r#"
[MD013]
line-length = 80
reflow = true
reflow-mode = "semantic-line-breaks"
"#;
    fs::write(&config_path, config_content).unwrap();

    // First pass
    let _output = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--fix")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl");

    let after_first = fs::read_to_string(&file_path).unwrap();

    // Second pass
    let _output = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--fix")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl");

    let after_second = fs::read_to_string(&file_path).unwrap();

    assert_eq!(
        after_first, after_second,
        "Second fix pass should produce identical output (idempotent)"
    );
}

#[test]
fn test_md013_semantic_line_breaks_check_detects_violations() {
    let dir = tempdir().unwrap();
    let file_path = dir.path().join("test.md");

    let content = "First sentence. Second sentence. Third sentence.\n";
    fs::write(&file_path, content).unwrap();

    let config_path = dir.path().join(".rumdl.toml");
    let config_content = r#"
[MD013]
line-length = 80
reflow = true
reflow-mode = "semantic-line-breaks"
"#;
    fs::write(&config_path, config_content).unwrap();

    let output = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl");

    let stdout = String::from_utf8_lossy(&output.stdout);
    // Should detect that the paragraph needs semantic line breaks
    assert!(
        stdout.contains("semantic line breaks"),
        "Should report semantic line breaks violation: {stdout}"
    );
}

#[test]
fn test_md013_issue_437_blockquote_reflow_regression() {
    let dir = tempdir().unwrap();
    let file_path = dir.path().join("issue_437.md");

    let content = r#"# Lorem

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed quam leo, rhoncus sodales erat sed. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed quam leo, rhoncus sodales erat sed.

> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed quam leo, rhoncus sodales erat sed. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed quam leo, rhoncus sodales erat sed.
"#;
    fs::write(&file_path, content).unwrap();

    let config_path = dir.path().join(".rumdl.toml");
    let config_content = r#"
[MD013]
line-length = 72
reflow = true
"#;
    fs::write(&config_path, config_content).unwrap();

    let _output = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--fix")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl");

    let after_first = fs::read_to_string(&file_path).unwrap();
    let quote_lines: Vec<&str> = after_first.lines().filter(|line| line.starts_with('>')).collect();

    assert!(
        quote_lines.len() >= 2,
        "Issue #437 regression: expected wrapped blockquote lines, got: {after_first}"
    );
    assert!(
        quote_lines.iter().all(|line| line.chars().count() <= 72),
        "Expected reflowed blockquote lines within limit: {after_first}"
    );

    // Idempotence: second pass should produce no further changes.
    let _output = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--fix")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl");

    let after_second = fs::read_to_string(&file_path).unwrap();
    assert_eq!(after_first, after_second);
}

#[test]
fn test_md013_issue_566_normalize_single_line_reflow_regression() {
    let dir = tempdir().unwrap();
    let file_path = dir.path().join("issue_566.md");

    let content = r#"# Lorem

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed quam leo, rhoncus sodales erat sed. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed quam leo, rhoncus sodales erat sed.

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed quam leo, rhoncus sodales erat sed. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
quam leo, rhoncus sodales erat sed.
"#;
    fs::write(&file_path, content).unwrap();

    let config_path = dir.path().join(".rumdl.toml");
    let config_content = r#"
[MD013]
line-length = 80
reflow = true
reflow-mode = "normalize"
"#;
    fs::write(&config_path, config_content).unwrap();

    let output = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("fmt")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl fmt");

    let exit_code = output.status.code().unwrap_or(-1);
    assert!(exit_code == 0 || exit_code == 1, "Unexpected exit code: {exit_code}");

    let fixed = fs::read_to_string(&file_path).unwrap();
    let paragraphs: Vec<&str> = fixed.split("\n\n").collect();
    assert_eq!(paragraphs.len(), 3, "Expected heading plus two paragraphs: {fixed}");

    for paragraph in paragraphs.iter().skip(1) {
        let lines: Vec<&str> = paragraph.lines().collect();
        assert!(lines.len() > 1, "Paragraph should be wrapped: {paragraph}");
        assert!(
            lines.iter().all(|line| line.chars().count() <= 80),
            "Wrapped lines should respect line length: {paragraph}"
        );
    }

    let second_pass = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("fmt")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl fmt on second pass");
    let second_exit_code = second_pass.status.code().unwrap_or(-1);
    assert!(
        second_exit_code == 0 || second_exit_code == 1,
        "Unexpected second-pass exit code: {second_exit_code}"
    );

    let after_second = fs::read_to_string(&file_path).unwrap();
    assert_eq!(fixed, after_second, "Normalize reflow should be idempotent");
}

/// Issue #493: Inline disable comments inside list items must be respected
/// even when reflow mode groups the list item as a single paragraph.
#[test]
fn test_md013_reflow_respects_inline_disable_in_list() {
    let dir = tempdir().unwrap();
    let file_path = dir.path().join("test.md");

    let content = "\
# Test

1. Lorem ipsum dolor sit amet.

   <!-- rumdl-capture -->
   <!-- rumdl-disable MD013 -->

   Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

   <!-- rumdl-restore -->
";
    fs::write(&file_path, content).unwrap();

    let config_path = dir.path().join(".rumdl.toml");
    fs::write(&config_path, "[global]\nline-length = 80\n\n[MD013]\nreflow = true\n").unwrap();

    let output = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--no-cache")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl");

    let combined = format!(
        "{}{}",
        String::from_utf8_lossy(&output.stdout),
        String::from_utf8_lossy(&output.stderr),
    );
    assert!(
        !combined.contains("MD013"),
        "MD013 should be suppressed by inline disable comment, got: {combined}"
    );
}

/// Issue #494: MkDocs inline attr lists must not be split across lines during reflow.
#[test]
fn test_md013_reflow_preserves_mkdocs_attr_list() {
    let dir = tempdir().unwrap();
    let file_path = dir.path().join("test.md");

    let content = "\
# Test

**Lorem ipsum dolor sit amet, consectetur adipiscing elit**{ style=\"color: red\" }, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
";
    fs::write(&file_path, content).unwrap();

    let config_path = dir.path().join(".rumdl.toml");
    fs::write(
        &config_path,
        "[global]\nflavor = \"mkdocs\"\nline-length = 80\n\n[MD013]\nreflow = true\n",
    )
    .unwrap();

    let output = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--fix")
        .arg("--no-cache")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl");

    assert!(output.status.success() || output.status.code() == Some(1));

    let result = fs::read_to_string(&file_path).unwrap();
    assert!(
        result.contains("{ style=\"color: red\" }"),
        "Attr list should be kept intact, got:\n{result}"
    );
    assert!(
        !result.contains("{ style=\"color:\n"),
        "Attr list should NOT be split across lines, got:\n{result}"
    );
}

/// Issue #494: Multiple attr lists on same line are all preserved.
#[test]
fn test_md013_reflow_preserves_multiple_attr_lists() {
    let dir = tempdir().unwrap();
    let file_path = dir.path().join("test.md");

    let content = "\
# Test

**Bold**{#my-id .highlight} and **more**{.other style=\"font-size: 2em\"} followed by text that makes this exceed eighty.
";
    fs::write(&file_path, content).unwrap();

    let config_path = dir.path().join(".rumdl.toml");
    fs::write(
        &config_path,
        "[global]\nflavor = \"mkdocs\"\nline-length = 80\n\n[MD013]\nreflow = true\n",
    )
    .unwrap();

    std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--fix")
        .arg("--no-cache")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl");

    let result = fs::read_to_string(&file_path).unwrap();
    assert!(
        result.contains("{#my-id .highlight}"),
        "First attr list should be intact, got:\n{result}"
    );
    assert!(
        result.contains("{.other style=\"font-size: 2em\"}"),
        "Second attr list should be intact, got:\n{result}"
    );
}

/// Issue #494: Non-attr-list braces are still treated as regular text.
#[test]
fn test_md013_reflow_attr_list_wrappable_in_standard_flavor() {
    let dir = tempdir().unwrap();
    let file_path = dir.path().join("test.md");

    // Use a long attr list that exceeds 80 chars on its own when attached to text,
    // forcing the reflow to break INSIDE the braces if treated as plain text.
    // In MkDocs mode the attr list is atomic; in standard mode it's wrappable.
    let content = "\
# Test

**Bold text here**{#section-identifier .primary-highlight .secondary-highlight style=\"background-color: red\"} and more text after it.
";
    fs::write(&file_path, content).unwrap();

    // Standard flavor (no MkDocs)
    let config_path_std = dir.path().join("standard.toml");
    fs::write(
        &config_path_std,
        "[global]\nline-length = 80\n\n[MD013]\nreflow = true\n",
    )
    .unwrap();

    std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--fix")
        .arg("--no-cache")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path_std)
        .output()
        .expect("Failed to execute rumdl");

    let result_std = fs::read_to_string(&file_path).unwrap();

    // In standard mode, the attr list is plain text and SHOULD be split across lines.
    // Verify no single line contains both the opening { and closing } of the attr list.
    let full_attr = "{#section-identifier .primary-highlight .secondary-highlight style=\"background-color: red\"}";
    let has_intact_attr = result_std.lines().any(|l| l.contains(full_attr));
    assert!(
        !has_intact_attr,
        "In standard flavor, long attr list should be split as regular text, got:\n{result_std}"
    );

    // Now test MkDocs flavor — same content, attr list must stay intact
    fs::write(&file_path, content).unwrap();
    let config_path_mkdocs = dir.path().join("mkdocs.toml");
    fs::write(
        &config_path_mkdocs,
        "[global]\nflavor = \"mkdocs\"\nline-length = 80\n\n[MD013]\nreflow = true\n",
    )
    .unwrap();

    std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--fix")
        .arg("--no-cache")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path_mkdocs)
        .output()
        .expect("Failed to execute rumdl");

    let result_mkdocs = fs::read_to_string(&file_path).unwrap();

    // In MkDocs mode, the attr list is atomic and must NOT be split.
    // Verify the full attr list appears on a single line.
    let has_intact_attr_mkdocs = result_mkdocs.lines().any(|l| l.contains(full_attr));
    assert!(
        has_intact_attr_mkdocs,
        "In MkDocs flavor, attr list must stay intact on one line, got:\n{result_mkdocs}"
    );
}

/// Issue #494: Non-attr-list braces are still treated as regular text.
#[test]
fn test_md013_reflow_does_not_treat_plain_braces_as_attr_list() {
    let dir = tempdir().unwrap();
    let file_path = dir.path().join("test.md");

    let content = "\
# Test

This line has {some random text in braces} that is not an attr list and should be treated as regular wrappable text here.
";
    fs::write(&file_path, content).unwrap();

    let config_path = dir.path().join(".rumdl.toml");
    fs::write(
        &config_path,
        "[global]\nflavor = \"mkdocs\"\nline-length = 80\n\n[MD013]\nreflow = true\n",
    )
    .unwrap();

    std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--fix")
        .arg("--no-cache")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl");

    let result = fs::read_to_string(&file_path).unwrap();
    // Plain braces should be wrappable — the line should be split
    let lines: Vec<&str> = result.lines().collect();
    let long_lines = lines.iter().filter(|l| l.len() > 80).count();
    assert_eq!(
        long_lines, 0,
        "Plain braces should be wrappable (no lines >80 chars), got:\n{result}"
    );
}

/// Verify that PyMdown block content is not flagged or rewritten by semantic-line-breaks reflow.
/// Covers all edge cases from GitHub issue #495:
/// - Block with title and newline-separated content
/// - Block without title
/// - No newline between options and content
/// - No newline between content and closing `///`
#[test]
fn test_md013_reflow_skips_pymdown_blocks() {
    let dir = tempdir().unwrap();
    let file_path = dir.path().join("test.md");

    let content = "\
# Test

/// details | Summary
    type: warning

Content inside the block.

///

/// details
    type: warning

Content inside the block.

///

/// details | Summary
    type: warning
Content inside the block.

///

/// details | Summary
    type: warning

Content inside the block.
///
";

    fs::write(&file_path, content).unwrap();

    let config_path = dir.path().join(".rumdl.toml");
    fs::write(
        &config_path,
        "[global]\nflavor = \"mkdocs\"\nline-length = 80\n\n[MD013]\nreflow = true\nreflow-mode = \"semantic-line-breaks\"\n",
    )
    .unwrap();

    // Check — should produce no warnings
    let output = std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--no-cache")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl");

    let stdout = String::from_utf8_lossy(&output.stdout);
    let stderr = String::from_utf8_lossy(&output.stderr);
    assert!(
        output.status.success(),
        "PyMdown block content should not trigger MD013 reflow.\nstdout: {stdout}\nstderr: {stderr}"
    );

    // Fix — content should be unchanged
    std::process::Command::new(env!("CARGO_BIN_EXE_rumdl"))
        .arg("check")
        .arg("--fix")
        .arg("--no-cache")
        .arg(&file_path)
        .arg("--config")
        .arg(&config_path)
        .output()
        .expect("Failed to execute rumdl");

    let result = fs::read_to_string(&file_path).unwrap();
    assert_eq!(
        result, content,
        "PyMdown block content should not be modified by reflow fix"
    );
}
