use super::*;

use pretty_assertions::assert_eq;

#[test]
fn test_empty() {
    let original = "";
    let message: Message = original.parse().unwrap();
    assert_eq!(
        message,
        Message {
            ..Default::default()
        }
    );
    assert_eq!(message.to_string().trim(), original);
}

#[test]
fn test_only_comments() {
    let original = "# hallo";
    let message: Message = original.parse().unwrap();
    assert_eq!(
        message,
        Message {
            comments: "hallo".to_string(),
            ..Default::default()
        }
    );
    assert_eq!(message.to_string().trim(), original);
}

#[test]
fn test_example_break() {
    let original = "feat: allow provided config object to extend other configs

BREAKING CHANGE: `extends` key in config file is now used for extending other config files";
    let message: Message = original.parse().unwrap();
    assert_eq!(
        message,
        Message {
            ctype: CommitType::Feature,
            description: "allow provided config object to extend other configs".to_string(),
            breaking: Breaking(vec![
                "`extends` key in config file is now used for extending other config files"
                    .to_string()
            ]),
            ..Default::default()
        }
    );
    assert_eq!(message.to_string().trim(), original);
}

#[test]
fn test_example_excl() {
    let original = "feat!: send an email to the customer when a product is shipped";
    let message: Message = original.parse().unwrap();
    assert_eq!(
        message,
        Message {
            ctype: CommitType::Feature,
            description: "send an email to the customer when a product is shipped".to_string(),
            is_breaking: true,
            ..Default::default()
        }
    );
    assert_eq!(message.to_string().trim(), original);
}

#[test]
fn test_example_excl_scope() {
    let original = "feat(api)!: send an email to the customer when a product is shipped";
    let message: Message = original.parse().unwrap();
    assert_eq!(
        message,
        Message {
            ctype: CommitType::Feature,
            scope: Some("api".to_string()),
            description: "send an email to the customer when a product is shipped".to_string(),
            is_breaking: true,
            ..Default::default()
        }
    );
    assert_eq!(message.to_string().trim(), original);
}

#[test]
fn test_example_excl_break() {
    let original = "feat!: drop support for Node 6

BREAKING CHANGE: use JavaScript features not available in Node 6.";
    let message: Message = original.parse().unwrap();
    assert_eq!(
        message,
        Message {
            ctype: CommitType::Feature,
            description: "drop support for Node 6".to_string(),
            is_breaking: true,
            breaking: Breaking(vec![
                "use JavaScript features not available in Node 6.".to_string()
            ]),
            ..Default::default()
        }
    );
    assert_eq!(message.to_string().trim(), original);
}

#[test]
fn test_simple() {
    let original = "docs: correct spelling of CHANGELOG";
    let message: Message = original.parse().unwrap();
    assert_eq!(
        message,
        Message {
            ctype: CommitType::Docs,
            description: "correct spelling of CHANGELOG".to_string(),
            ..Default::default()
        }
    );
    assert_eq!(message.to_string().trim(), original);
}

#[test]
fn test_scope() {
    let original = "feat(lang): add Polish language";
    let message: Message = original.parse().unwrap();
    assert_eq!(
        message,
        Message {
            ctype: CommitType::Feature,
            scope: Some("lang".to_string()),
            description: "add Polish language".to_string(),
            ..Default::default()
        }
    );
    assert_eq!(message.to_string().trim(), original);
}

#[test]
fn test_empty_scope() {
    let original = "feat(): add Polish language";
    let message: Message = original.parse().unwrap();
    assert_eq!(
        message,
        Message {
            ctype: CommitType::Feature,
            scope: Some(String::new()),
            description: "add Polish language".to_string(),
            ..Default::default()
        }
    );
    assert_eq!(message.to_string().trim(), original);
}

#[test]
fn test_complex() {
    let original = "fix: prevent racing of requests

Introduce a request id and a reference to latest request. Dismiss
incoming responses other than from latest request.

Remove timeouts which were used to mitigate the racing issue but are
obsolete now.

Reviewed-by: Z
Refs: #123";
    let message: Message = original.parse().unwrap();
    assert_eq!(
        message,
        Message {
            ctype: CommitType::Fix,
            description: "prevent racing of requests".to_string(),
            body: "Introduce a request id and a reference to latest request. Dismiss
incoming responses other than from latest request.

Remove timeouts which were used to mitigate the racing issue but are
obsolete now."
                .to_string(),
            footer: Footer(vec![
                ("Reviewed-by".to_string(), "Z".to_string()),
                ("Refs".to_string(), "#123".to_string()),
            ]),
            ..Default::default()
        }
    );
    assert_eq!(message.to_string().trim(), original);
}

#[test]
fn test_complex_with_comments() {
    let original = "fix: prevent racing of requests

Introduce a request id and a reference to latest request. Dismiss
incoming responses other than from latest request.

Remove timeouts which were used to mitigate the racing issue but are
obsolete now.

BREAKING CHANGE: use JavaScript features not available in Node 6.

Reviewed-by: Z
Refs: #123

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Mon Mar 16 23:14:28 2026 +0100
#
# On branch develop
# Your branch is up to date with 'origin/develop'.
#
# Changes to be committed:
#	modified:   .devcontainer.json
#	new file:   .vscode/launch.json
#	modified:   Cargo.lock
#	modified:   Cargo.toml
#	renamed:    src/commit.rs -> src/commit/mod.rs
#	new file:   src/commit/parse.rs
#	new file:   src/commit/test.rs
#	modified:   src/main.rs
#
# Changes not staged for commit:
#	modified:   src/commit/mod.rs
#	modified:   src/commit/parse.rs
#	modified:   src/main.rs
#
# Untracked files:
#	test.txt";
    let message: Message = original.parse().unwrap();
    assert_eq!(
        message,
        Message {
            ctype: CommitType::Fix,
            description: "prevent racing of requests".to_string(),
            body: "Introduce a request id and a reference to latest request. Dismiss
incoming responses other than from latest request.

Remove timeouts which were used to mitigate the racing issue but are
obsolete now."
                .to_string(),
            footer: Footer(vec![
                ("Reviewed-by".to_string(), "Z".to_string()),
                ("Refs".to_string(), "#123".to_string()),
            ]),
            breaking: Breaking(vec![
                "use JavaScript features not available in Node 6.".to_string()
            ]),
            comments: "Please enter the commit message for your changes. Lines starting
with '#' will be ignored, and an empty message aborts the commit.

Date:      Mon Mar 16 23:14:28 2026 +0100

On branch develop
Your branch is up to date with 'origin/develop'.

Changes to be committed:
	modified:   .devcontainer.json
	new file:   .vscode/launch.json
	modified:   Cargo.lock
	modified:   Cargo.toml
	renamed:    src/commit.rs -> src/commit/mod.rs
	new file:   src/commit/parse.rs
	new file:   src/commit/test.rs
	modified:   src/main.rs

Changes not staged for commit:
	modified:   src/commit/mod.rs
	modified:   src/commit/parse.rs
	modified:   src/main.rs

Untracked files:
	test.txt"
                .to_string(),
            ..Default::default()
        }
    );
    assert_eq!(message.to_string().trim(), original);
}

#[test]
fn test_merge() {
    let original = "Merge branch 'develop' into release

# It looks like you may be committing a merge.
# If this is not correct, please run
#       git update-ref -d MERGE_HEAD
# and try again.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch release
# Your branch is up to date with 'origin/release'.
#
# All conflicts fixed but you are still merging.
#
# Changes to be committed:
#       new file:   .devcontainer.json
#       new file:   .gitignore
#       new file:   .gitlab-ci.yml
#       new file:   .releaserc.json
#       new file:   .vscode/launch.json
#       new file:   Cargo.lock
#       new file:   Cargo.toml
#       new file:   src/commit/mod.rs
#       new file:   src/commit/parse.rs
#       new file:   src/commit/test.rs
#       new file:   src/main.rs
#       new file:   test.txt";
    let message: Message = original.parse().unwrap();
    assert_eq!(
        message,
        Message {
            ctype: CommitType::None,
            description: "Merge branch 'develop' into release".to_string(),
            comments: "It looks like you may be committing a merge.
If this is not correct, please run
      git update-ref -d MERGE_HEAD
and try again.
Please enter the commit message for your changes. Lines starting
with '#' will be ignored, and an empty message aborts the commit.

On branch release
Your branch is up to date with 'origin/release'.

All conflicts fixed but you are still merging.

Changes to be committed:
      new file:   .devcontainer.json
      new file:   .gitignore
      new file:   .gitlab-ci.yml
      new file:   .releaserc.json
      new file:   .vscode/launch.json
      new file:   Cargo.lock
      new file:   Cargo.toml
      new file:   src/commit/mod.rs
      new file:   src/commit/parse.rs
      new file:   src/commit/test.rs
      new file:   src/main.rs
      new file:   test.txt"
                .to_string(),
            ..Default::default()
        }
    );
    assert_eq!(message.to_string().trim(), original);
}
