use indoc::indoc;
use insta::assert_snapshot;

use super::assert_valid_toml;
use crate::{format_toml, Settings};

fn default_settings() -> Settings {
    Settings {
        column_width: 120,
        indent: 2,
        keep_full_version: false,
        max_supported_python: (3, 9),
        min_supported_python: (3, 9),
        generate_python_version_classifiers: false,
        table_format: String::from("short"),
        sub_table_spacing: String::new(),
        separate_root_table: String::from("\n"),
        expand_tables: vec![],
        collapse_tables: vec![],
        skip_wrap_for_keys: vec![],
    }
}

fn long_format_settings() -> Settings {
    Settings {
        table_format: String::from("long"),
        ..default_settings()
    }
}

fn format_toml_helper(
    start: &str,
    indent: usize,
    keep_full_version: bool,
    max_supported_python: (u8, u8),
    generate_python_version_classifiers: bool,
) -> String {
    let settings = Settings {
        indent,
        keep_full_version,
        max_supported_python,
        generate_python_version_classifiers,
        ..default_settings()
    };
    let result = format_toml(start, &settings);
    assert_valid_toml(&result);
    result
}

#[test]
fn test_format_toml_simple() {
    let start = indoc! {r#"
    # comment
    a= "b"
    [project]
    name="alpha"
    dependencies=[" e >= 1.5.0"]
    [build-system]
    build-backend="backend"
    requires=[" c >= 1.5.0", "d == 2.0.0"]
    [dependency-groups]
    test=["p>1.0.0"]
    [tool.mypy]
    mk="mv"
    "#};
    let res = format_toml_helper(start, 2, false, (3, 13), true);
    assert_snapshot!(res, @r#"
    # comment
    a = "b"

    [build-system]
    build-backend = "backend"
    requires = [ "c>=1.5", "d==2" ]

    [project]
    name = "alpha"
    classifiers = [
      "Programming Language :: Python :: 3 :: Only",
      "Programming Language :: Python :: 3.9",
      "Programming Language :: Python :: 3.10",
      "Programming Language :: Python :: 3.11",
      "Programming Language :: Python :: 3.12",
      "Programming Language :: Python :: 3.13",
    ]
    dependencies = [ "e>=1.5" ]

    [dependency-groups]
    test = [ "p>1" ]

    [tool.mypy]
    mk = "mv"
    "#);
}

#[test]
fn test_format_toml_scripts() {
    let start = indoc! {r#"
    [project.scripts]
    c = "d"
    a = "b"
    "#};
    let res = format_toml_helper(start, 2, true, (3, 9), true);
    assert_snapshot!(res, @r#"
    [project]
    classifiers = [
      "Programming Language :: Python :: 3 :: Only",
      "Programming Language :: Python :: 3.9",
    ]
    scripts.a = "b"
    scripts.c = "d"
    "#);
}

#[test]
fn test_expand_tables_with_project() {
    let start = indoc! {r#"
        [project]
        name = "example"
        optional-dependencies.dev = ["pytest"]
        urls.homepage = "https://example.com"
        "#};
    let settings = Settings {
        expand_tables: vec![String::from("project")],
        ..default_settings()
    };
    let got = format_toml(start, &settings);
    assert_snapshot!(got, @r#"
    [project]
    name = "example"

    [project.optional-dependencies]
    dev = [ "pytest" ]

    [project.urls]
    homepage = "https://example.com"
    "#);
}

#[test]
fn test_collapse_project_authors() {
    let start = indoc! {r#"
        [project]
        name = "example"
        [[project.authors]]
        name = "John Doe"
        email = "john@example.com"
        "#};
    let settings = Settings {
        collapse_tables: vec![String::from("project.authors")],
        ..long_format_settings()
    };
    let got = format_toml(start, &settings);
    assert_snapshot!(got, @r#"
    [project]
    name = "example"
    authors = [ { name = "John Doe", email = "john@example.com" } ]
    "#);
}

#[test]
fn test_collapse_project_maintainers() {
    let start = indoc! {r#"
        [project]
        name = "example"
        [[project.maintainers]]
        name = "Jane Doe"
        email = "jane@example.com"
        "#};
    let settings = Settings {
        collapse_tables: vec![String::from("project.maintainers")],
        ..long_format_settings()
    };
    let got = format_toml(start, &settings);
    assert_snapshot!(got, @r#"
    [project]
    name = "example"
    maintainers = [ { name = "Jane Doe", email = "jane@example.com" } ]
    "#);
}

#[test]
fn test_table_format_long_with_entry_points() {
    let start = indoc! {r#"
        [project]
        name = "example"
        entry-points."console_scripts".mycli = "pkg:main"
        entry-points."console_scripts".othercli = "pkg:other"
        "#};
    let got = format_toml(start, &long_format_settings());
    assert_snapshot!(got, @r#"
    [project]
    name = "example"
    [project.entry-points]
    console_scripts.mycli = "pkg:main"
    console_scripts.othercli = "pkg:other"
    "#);
}

#[test]
fn test_expand_project_authors() {
    let start = indoc! {r#"
        [project]
        name = "example"
        authors = [
          { name = "John Doe", email = "john@example.com" },
          { name = "Jane Doe", email = "jane@example.com" },
        ]
        "#};
    let settings = Settings {
        expand_tables: vec![String::from("project.authors")],
        ..default_settings()
    };
    let got = format_toml(start, &settings);
    assert_snapshot!(got, @r#"
    [project]
    name = "example"

    [[project.authors]]
    name = "John Doe"
    email = "john@example.com"

    [[project.authors]]
    name = "Jane Doe"
    email = "jane@example.com"
    "#);
}

#[test]
fn test_expand_project_maintainers() {
    let start = indoc! {r#"
        [project]
        name = "example"
        maintainers = [
          { name = "Bob Smith", email = "bob@example.com" },
          { name = "Alice Jones", email = "alice@example.com" },
        ]
        "#};
    let settings = Settings {
        expand_tables: vec![String::from("project.maintainers")],
        ..default_settings()
    };
    let got = format_toml(start, &settings);
    assert_snapshot!(got, @r#"
    [project]
    name = "example"

    [[project.maintainers]]
    name = "Bob Smith"
    email = "bob@example.com"

    [[project.maintainers]]
    name = "Alice Jones"
    email = "alice@example.com"
    "#);
}

#[test]
fn test_expand_single_author() {
    let start = indoc! {r#"
        [project]
        name = "example"
        authors = [
          { name = "John Doe", email = "john@example.com" },
        ]
        "#};
    let settings = Settings {
        expand_tables: vec![String::from("project.authors")],
        ..default_settings()
    };
    let got = format_toml(start, &settings);
    assert_snapshot!(got, @r#"
    [project]
    name = "example"

    [[project.authors]]
    name = "John Doe"
    email = "john@example.com"
    "#);
}
#[test]
fn test_collapse_authors_with_url_field() {
    let start = indoc! {r#"
        [project]
        name = "test"
        [[project.authors]]
        name = "Bob"
        email = "bob@example.com"
        url = "https://bob.com"
        [[project.authors]]
        name = "Alice"
        email = "alice@example.com"
        "#};
    let got = format_toml(start, &default_settings());
    assert_snapshot!(got, @r#"
    [project]
    name = "test"
    authors = [
      { name = "Bob", email = "bob@example.com", url = "https://bob.com" },
      { name = "Alice", email = "alice@example.com" }
    ]
    "#);
}
#[test]
fn test_collapse_empty_authors() {
    let start = indoc! {r#"
        [project]
        name = "test"
        [[project.authors]]
        [[project.authors]]
        "#};
    let got = format_toml(start, &default_settings());
    assert_snapshot!(got, @r#"
    [project]
    name = "test"

    [[project.authors]]

    [[project.authors]]
    "#);
}

#[test]
fn test_collapse_authors_without_trailing_newline() {
    let start = "[project]\nname = \"test\"\n[[project.authors]]\nname = \"Alice\"\nemail = \"alice@example.com\"";
    let got = format_toml(start, &default_settings());
    assert!(got.contains("authors = ["));
    assert!(got.contains("{ name = \"Alice\", email = \"alice@example.com\" }"));
}

#[test]
fn test_collapse_authors_compact_parent() {
    let start =
        "[project]\nname=\"test\"\nversion=\"1.0\"\n[[project.authors]]\nname=\"Alice\"\nemail=\"alice@example.com\"";
    let got = format_toml(start, &default_settings());
    assert!(got.contains("authors = ["));
}

#[test]
fn test_expand_authors_already_expanded() {
    let start = indoc! {r#"
        [project]
        name = "example"
        [[project.authors]]
        name = "John Doe"
        email = "john@example.com"
        "#};
    let settings = Settings {
        expand_tables: vec![String::from("project.authors")],
        ..long_format_settings()
    };
    let got = format_toml(start, &settings);
    assert!(got.contains("[[project.authors]]"));
    assert!(got.contains("name = \"John Doe\""));
}

#[test]
fn test_issue_146_expand_specific_subtable() {
    let start = indoc! {r#"
        [project]
        name = "test"
        [project.optional-dependencies]
        a = ["b", "c"]
        [project.urls]
        homepage = "https://example.com"
        "#};
    let settings = Settings {
        column_width: 120,
        indent: 4,
        keep_full_version: true,
        max_supported_python: (3, 14),
        min_supported_python: (3, 14),
        expand_tables: vec![String::from("project.optional-dependencies")],
        ..default_settings()
    };
    let got = format_toml(start, &settings);
    assert!(
        got.contains("[project.optional-dependencies]"),
        "optional-dependencies should stay expanded"
    );
    assert!(got.contains("urls.homepage ="), "urls should be collapsed");
}

#[test]
fn test_css_specificity_more_specific_wins() {
    let start = indoc! {r#"
        [project]
        name = "test"
        [project.urls]
        homepage = "https://example.com"
        [project.optional-dependencies]
        dev = ["pytest"]
        "#};
    let settings = Settings {
        indent: 4,
        keep_full_version: true,
        expand_tables: vec![String::from("project.urls")],
        collapse_tables: vec![String::from("project")],
        ..long_format_settings()
    };
    let got = format_toml(start, &settings);
    assert!(
        got.contains("[project.urls]"),
        "project.urls should be expanded (specific)"
    );
    assert!(
        got.contains("optional-dependencies.dev ="),
        "optional-dependencies should be collapsed (inherits project)"
    );
}

#[test]
fn test_nested_table_specificity() {
    use crate::TableFormatConfig;
    use std::collections::HashSet;

    let mut expand = HashSet::new();
    expand.insert(String::from("project.entry-points.special"));

    let mut collapse = HashSet::new();
    collapse.insert(String::from("project.entry-points"));

    let config = TableFormatConfig {
        default_collapse: false,
        expand_tables: expand,
        collapse_tables: collapse,
    };

    assert!(
        config.should_collapse("project.entry-points"),
        "project.entry-points should collapse"
    );
    assert!(
        config.should_collapse("project.entry-points.tox"),
        "project.entry-points.tox inherits collapse"
    );
    assert!(
        !config.should_collapse("project.entry-points.special"),
        "project.entry-points.special should expand"
    );
}

#[test]
fn test_parent_inheritance() {
    use crate::TableFormatConfig;
    use std::collections::HashSet;

    let mut expand = HashSet::new();
    expand.insert(String::from("project"));

    let config = TableFormatConfig {
        default_collapse: true,
        expand_tables: expand,
        collapse_tables: HashSet::new(),
    };

    assert!(!config.should_collapse("project"), "project should expand");
    assert!(
        !config.should_collapse("project.urls"),
        "project.urls inherits expand from project"
    );
    assert!(
        !config.should_collapse("project.optional-dependencies"),
        "project.optional-dependencies inherits expand"
    );
}

#[test]
fn test_default_collapse_fallback() {
    use crate::TableFormatConfig;
    use std::collections::HashSet;

    let config = TableFormatConfig {
        default_collapse: true,
        expand_tables: HashSet::new(),
        collapse_tables: HashSet::new(),
    };

    assert!(config.should_collapse("project"));
    assert!(config.should_collapse("project.urls"));
    assert!(config.should_collapse("tool.ruff.lint"));
}

#[test]
fn test_issue_146_deeply_nested_ruff_table() {
    let start = indoc! {r#"
        [tool.ruff.lint.flake8-tidy-imports.banned-api]
        "collections.namedtuple".msg = "Use typing.NamedTuple instead"
        "#};
    let settings = Settings {
        column_width: 120,
        indent: 4,
        keep_full_version: true,
        max_supported_python: (3, 14),
        min_supported_python: (3, 14),
        expand_tables: vec![String::from("tool.ruff.lint.flake8-tidy-imports.banned-api")],
        ..default_settings()
    };
    let got = format_toml(start, &settings);
    assert!(
        got.contains("[tool.ruff.lint.flake8-tidy-imports.banned-api]"),
        "deeply nested ruff table should stay expanded. Got:\n{got}"
    );
}

#[test]
fn test_no_duplicate_requires() {
    let start = indoc! {r#"
        [build-system]
        build-backend = "backend"
        requires = ["c", "d"]
    "#};
    let got = format_toml(start, &default_settings());
    let count = got.matches("requires").count();
    assert_eq!(count, 1, "requires should appear exactly once, but got:\n{}", got);
}

#[test]
fn test_table_format_long_removes_blank_lines_between_same_group() {
    let start = indoc! {r#"
        [project]
        name = "test"

        [project.urls]
        homepage = "https://example.com"

        [project.optional-dependencies]
        dev = ["pytest"]
        "#};
    let got = format_toml(start, &long_format_settings());
    assert_snapshot!(got, @r#"
    [project]
    name = "test"
    [project.optional-dependencies]
    dev = [ "pytest" ]
    [project.urls]
    homepage = "https://example.com"
    "#);
}

#[test]
fn test_table_format_long_with_tool_tables() {
    let start = indoc! {r#"
        [tool.ruff]
        line-length = 120

        [tool.ruff.lint]
        select = ["E", "W"]

        [tool.mypy]
        strict = true
        "#};
    let got = format_toml(start, &long_format_settings());
    assert_snapshot!(got, @r#"
    [tool.ruff]
    line-length = 120
    [tool.ruff.lint]
    select = [ "E", "W" ]

    [tool.mypy]
    strict = true
    "#);
}

#[test]
fn test_table_format_long_preserves_blank_lines_between_different_groups() {
    let start = indoc! {r#"
        [build-system]
        requires = ["setuptools"]

        [project]
        name = "test"
        "#};
    let got = format_toml(start, &long_format_settings());
    assert_snapshot!(got, @r#"
    [build-system]
    requires = [ "setuptools" ]

    [project]
    name = "test"
    "#);
}

#[test]
fn test_extract_table_names_from_array_tables() {
    let start = indoc! {r#"
        [project]
        name = "test"

        [[project.authors]]
        name = "John"
        "#};
    let settings = Settings {
        expand_tables: vec![String::from("project.authors")],
        ..long_format_settings()
    };
    let got = format_toml(start, &settings);
    assert_snapshot!(got, @r#"
    [project]
    name = "test"
    [[project.authors]]
    name = "John"
    "#);
}

#[test]
fn test_format_with_trailing_newline_preserved() {
    let start = "[project]\nname = \"test\"\n";
    let got = format_toml(start, &default_settings());
    assert_snapshot!(got, @r#"
    [project]
    name = "test"
    "#);
}

#[test]
fn test_tool_prefix_extraction_with_dotted_keys() {
    let start = indoc! {r#"
        [tool.coverage.run]
        branch = true

        [tool.coverage.report]
        precision = 2
        "#};
    let got = format_toml(start, &long_format_settings());
    assert_snapshot!(got, @"
    [tool.coverage.report]
    precision = 2
    [tool.coverage.run]
    branch = true
    ");
}

#[test]
fn test_should_collapse_with_no_dot_in_name() {
    use crate::TableFormatConfig;
    use std::collections::HashSet;

    let config = TableFormatConfig {
        default_collapse: true,
        expand_tables: HashSet::new(),
        collapse_tables: HashSet::new(),
    };

    assert!(config.should_collapse("project"));
    assert!(config.should_collapse("build-system"));
}

#[test]
fn test_format_with_non_table_lines_between_headers() {
    let start = indoc! {r#"
        [project]
        name = "test"
        version = "1.0"

        [project.urls]
        homepage = "https://example.com"
        "#};
    let got = format_toml(start, &long_format_settings());
    assert_snapshot!(got, @r#"
    [project]
    name = "test"
    version = "1.0"
    [project.urls]
    homepage = "https://example.com"
    "#);
}

#[test]
fn test_settings_new() {
    let settings = Settings::new(
        120,
        4,
        true,
        (3, 13),
        (3, 9),
        true,
        String::from("short"),
        String::from("\n"),
        String::from("\n\n"),
        vec![String::from("project.urls")],
        vec![String::from("project.authors")],
        vec![],
    );
    assert_eq!(settings.column_width, 120);
    assert_eq!(settings.indent, 4);
    assert!(settings.keep_full_version);
    assert_eq!(settings.max_supported_python, (3, 13));
    assert_eq!(settings.min_supported_python, (3, 9));
    assert!(settings.generate_python_version_classifiers);
    assert_eq!(settings.table_format, "short");
    assert_eq!(settings.sub_table_spacing, "\n");
    assert_eq!(settings.separate_root_table, "\n\n");
    assert_eq!(settings.expand_tables, vec!["project.urls"]);
    assert_eq!(settings.collapse_tables, vec!["project.authors"]);
}

#[test]
fn test_table_format_config_from_settings() {
    use crate::TableFormatConfig;

    let settings = Settings::new(
        120,
        2,
        false,
        (3, 12),
        (3, 9),
        false,
        String::from("short"),
        String::new(),
        String::from("\n"),
        vec![String::from("tool.ruff")],
        vec![String::from("project")],
        vec![],
    );
    let config = TableFormatConfig::from_settings(&settings);
    assert!(config.default_collapse);
    assert!(config.expand_tables.contains("tool.ruff"));
    assert!(config.collapse_tables.contains("project"));
}

#[test]
fn test_lib_module_registration() {
    use pyo3::types::PyAnyMethods;

    pyo3::Python::initialize();
    pyo3::Python::attach(|py| {
        let module = pyo3::types::PyModule::new(py, "_lib").unwrap();
        crate::_lib(&module.as_borrowed()).unwrap();

        assert!(module.hasattr("format_toml").unwrap());
        assert!(module.hasattr("Settings").unwrap());
    });
}

#[test]
fn test_idempotent_formatting() {
    let start = indoc! {r#"
        [project]
        name = "test"
        description = "This is a long description string that needs to exceed the default column width of one hundred and twenty characters to trigger wrapping."
    "#};
    let settings = default_settings();
    let first = format_toml(start, &settings);
    let second = format_toml(&first, &settings);
    let third = format_toml(&second, &settings);
    assert_eq!(first, second, "formatting should be idempotent (first->second)");
    assert_eq!(second, third, "formatting should be idempotent (second->third)");
}

#[test]
fn test_issue_186_single_quote_with_comments() {
    let start = indoc! {r#"
    [tool.something]
    items = [
        'first',
        # A comment
        'second',
    ]
    "#};
    let got = format_toml(start, &default_settings());
    assert_snapshot!(got, @r#"
    [tool.something]
    items = [
      "first",
      # A comment
      "second",
    ]
    "#);
}

#[test]
fn test_remove_blank_lines_between_same_group_tables_long_format() {
    let start = indoc! {r#"
    [tool.ruff]
    line-length = 100

    [tool.ruff.lint]
    select = ["ALL"]

    [tool.ruff.format]
    quote-style = "double"
    "#};
    let got = format_toml(start, &long_format_settings());
    assert_snapshot!(got, @r#"
    [tool.ruff]
    line-length = 100
    [tool.ruff.format]
    quote-style = "double"
    [tool.ruff.lint]
    select = [ "ALL" ]
    "#);
}

#[test]
fn test_table_key_without_prefix_match_long_format() {
    let start = indoc! {r#"
    [custom]
    key = "value"

    [custom.nested]
    other = "data"
    "#};
    let got = format_toml(start, &long_format_settings());
    assert_snapshot!(got, @r#"
    [custom]
    key = "value"
    [custom.nested]
    other = "data"
    "#);
}

#[test]
fn test_sub_table_spacing_blank_line() {
    let start = indoc! {r#"
        [tool.ruff]
        line-length = 120

        [tool.ruff.lint]
        select = ["E", "W"]

        [tool.mypy]
        strict = true
        "#};
    let settings = Settings {
        sub_table_spacing: String::from("\n"),
        ..long_format_settings()
    };
    let got = format_toml(start, &settings);
    assert_snapshot!(got, @r#"
    [tool.ruff]
    line-length = 120

    [tool.ruff.lint]
    select = [ "E", "W" ]

    [tool.mypy]
    strict = true
    "#);
}

#[test]
fn test_sub_table_spacing_with_project_tables() {
    let start = indoc! {r#"
        [project]
        name = "test"

        [project.urls]
        homepage = "https://example.com"

        [project.optional-dependencies]
        dev = ["pytest"]
        "#};
    let settings = Settings {
        sub_table_spacing: String::from("\n"),
        ..long_format_settings()
    };
    let got = format_toml(start, &settings);
    assert_snapshot!(got, @r#"
    [project]
    name = "test"

    [project.optional-dependencies]
    dev = [ "pytest" ]

    [project.urls]
    homepage = "https://example.com"
    "#);
}

#[test]
fn test_issue_402_sub_table_spacing_two_blank_lines() {
    let start = indoc! {r#"
        [tool.uv.sources]
        pkg = { workspace = true }

        [tool.uv.workspace]
        members = ["a", "b"]

        [tool.pyproject-fmt]
        indent = 4
        "#};
    let settings = Settings {
        sub_table_spacing: String::from("\n\n"),
        ..long_format_settings()
    };
    let got = format_toml(start, &settings);
    assert_snapshot!(got, @r#"
    [tool.uv.sources]
    pkg = { workspace = true }


    [tool.uv.workspace]
    members = [ "a", "b" ]

    [tool.pyproject-fmt]
    indent = 4
    "#);
}

#[test]
fn test_issue_402_separate_root_table_two_blank_lines() {
    let start = indoc! {r#"
        [build-system]
        requires = ["hatchling"]

        [project]
        name = "test"
        "#};
    let settings = Settings {
        separate_root_table: String::from("\n\n"),
        ..default_settings()
    };
    let got = format_toml(start, &settings);
    assert_snapshot!(got, @r#"
    [build-system]
    requires = [ "hatchling" ]


    [project]
    name = "test"
    "#);
}

#[test]
fn test_issue_217_mixed_quotes_idempotent() {
    let start = indoc! {r#"
    [project]
    name = "flexget"
    requires-python = ">=3.14"
    classifiers = [
      "Programming Language :: Python :: 3 :: Only",
      "Programming Language :: Python :: 3.14",
    ]

    [tool.ruff]
    lint.per-file-ignores.'docs/scripts/*' = [ "T20" ]
    lint.per-file-ignores.'tests/*' = [ "T20" ]
    lint.per-file-ignores."flexget/*" = [ "PTH" ] # TODO
    "#};
    let settings = Settings {
        keep_full_version: true,
        max_supported_python: (3, 14),
        min_supported_python: (3, 14),
        ..default_settings()
    };
    let first = format_toml(start, &settings);
    assert_valid_toml(&first);
    let second = format_toml(&first, &settings);
    assert_eq!(first, second, "formatting should be idempotent");
    assert_snapshot!(first, @r#"
    [project]
    name = "flexget"
    requires-python = ">=3.14"
    classifiers = [
      "Programming Language :: Python :: 3 :: Only",
      "Programming Language :: Python :: 3.14",
    ]

    [tool.ruff]
    lint.per-file-ignores."docs/scripts/*" = [ "T20" ]
    lint.per-file-ignores."flexget/*" = [ "PTH" ]  # TODO
    lint.per-file-ignores."tests/*" = [ "T20" ]
    "#);
}

#[test]
fn test_issue_217_full_pyproject_idempotent() {
    let start = std::fs::read_to_string(
        std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("rust/src/tests/data/issue-217.toml"),
    )
    .unwrap();
    let settings = Settings {
        keep_full_version: true,
        max_supported_python: (3, 14),
        min_supported_python: (3, 10),
        ..default_settings()
    };
    let first = format_toml(&start, &settings);
    assert_valid_toml(&first);
    let second = format_toml(&first, &settings);
    assert_eq!(first, second, "formatting should be idempotent");
    assert_snapshot!(first);
}

#[test]
fn test_issue_299_pixi_workspace_collapse_with_keys() {
    let start = indoc! {r#"
    [project]
    name = "x"
    version = "0.1.0"

    [tool.pixi.workspace]
    name = "my-project"
    "#};
    let got = format_toml(start, &default_settings());
    assert_valid_toml(&got);
    assert_snapshot!(got, @r#"
    [project]
    name = "x"
    version = "0.1.0"

    [tool.pixi]
    workspace.name = "my-project"
    "#);
}

#[test]
fn test_issue_299_pixi_workspace_collapse_empty() {
    let start = indoc! {r#"
    [project]
    name = "x"
    version = "0.1.0"

    [tool.pixi.workspace]
    "#};
    let got = format_toml(start, &default_settings());
    assert_valid_toml(&got);
    assert_snapshot!(got, @r#"
    [project]
    name = "x"
    version = "0.1.0"

    [tool.pixi]
    workspace = {}
    "#);
}

#[test]
fn test_issue_202_preserve_inline_comment_after_array() {
    let start = indoc! {r#"
    [tool.uv]
    lint.per-file-ignores."docs/**/*.py" = [ "INP001" ] # No __init__.py in docs
    "#};
    let got = format_toml(start, &default_settings());
    assert_snapshot!(got, @r#"
    [tool.uv]
    lint.per-file-ignores."docs/**/*.py" = [ "INP001" ]  # No __init__.py in docs
    "#);
}

#[test]
fn test_issue_376_collapse_with_comments_stays_valid() {
    let start = indoc! {r#"
        [[tool.uv.index]]
        name = "pypi"
        url = "https://pypi.org/simple"
        # TODO: uncomment once ready
        # default = true
        authenticate = "never"

        [[tool.uv.index]]
        name = "company-master"
        url = "https://dl.cloudsmith.io/x"
        # ignore-error-codes = [400, 401, 403]
        authenticate = "always"
    "#};
    let mut settings = default_settings();
    settings.collapse_tables = vec![String::from("tool.uv.index")];
    let result = format_toml(start, &settings);
    assert_valid_toml(&result);
    insta::assert_snapshot!(result, @r#"
    [[tool.uv.index]]
    name = "pypi"
    url = "https://pypi.org/simple"
    # TODO: uncomment once ready
    # default = true
    authenticate = "never"

    [[tool.uv.index]]
    name = "company-master"
    url = "https://dl.cloudsmith.io/x"
    # ignore-error-codes = [ 400, 401, 403 ]
    authenticate = "always"
    "#);
}

#[test]
fn test_wide_array_of_tables_under_implicit_parent() {
    let start = indoc! {r#"
        [[tool.demo.labels.file-rules]]
        any-glob-to-any-file = ["src/managers/apt*", "src/managers/dpkg*", "src/managers/opkg*", "tests/*apt*", "tests/*dpkg*", "tests/*opkg*"]
    "#};
    let result = format_toml(start, &default_settings());
    assert_valid_toml(&result);
    insta::assert_snapshot!(result, @r#"
    [[tool.demo.labels.file-rules]]
    any-glob-to-any-file = [
      "src/managers/apt*",
      "src/managers/dpkg*",
      "src/managers/opkg*",
      "tests/*apt*",
      "tests/*dpkg*",
      "tests/*opkg*"
    ]
    "#);
}

#[test]
fn test_wide_array_of_tables_under_explicit_empty_parent() {
    let start = indoc! {r#"
        [tool.demo.labels]
        [[tool.demo.labels.file-rules]]
        any-glob-to-any-file = ["src/managers/apt*", "src/managers/dpkg*", "src/managers/opkg*", "tests/*apt*", "tests/*dpkg*", "tests/*opkg*"]
    "#};
    let result = format_toml(start, &default_settings());
    assert_valid_toml(&result);
    insta::assert_snapshot!(result, @r#"
    [tool.demo.labels]
    [[tool.demo.labels.file-rules]]
    any-glob-to-any-file = [
      "src/managers/apt*",
      "src/managers/dpkg*",
      "src/managers/opkg*",
      "tests/*apt*",
      "tests/*dpkg*",
      "tests/*opkg*"
    ]
    "#);
}
