use chumsky::Parser;

use crate::{
    __internal__parse_include_str, __internal__parse_with_path, __internal__span_macro_include_str,
    ast::{
        Command, CurlyKind, Expression, IndentationMarker, Literal, MemberAccess, SourceFile,
        StringLiteralComponent, Template, TemplateBody, TemplateContent,
        TemplateContentEscapeSequence, TemplateLine, TemplateLineNewline, Type, TypeDefinition,
    },
    parse::source_file::{source_file, source_file_whitespace_or_comments},
};

use pretty_assertions::assert_eq;

#[test]
fn test_parse_source_file_whitespace_or_comments() {
    assert!(!__internal__parse_with_path!(
        source_file_whitespace_or_comments(),
        "<test>",
        " // comments galore!\n \t /* hello // nested comment\n/* more nested */ still comment */"
    )
    .has_errors());
}

#[test]
#[allow(clippy::too_many_lines)]
fn test_parse_source_file() {
    __internal__span_macro_include_str!(
        crate::Span,
        "../../../../testdata/source_files/stress_test.cctmpl"
    );

    assert_eq!(
        __internal__parse_include_str!(source_file(), "../../../../testdata/source_files/stress_test.cctmpl")
            .unwrap(),
        SourceFile {
            type_defs: vec![
                (
                    TypeDefinition {
                        name: (
                            "Blub",
                            s!(344..348),
                        ),
                        ty: (
                            Type::Options(
                                vec![
                                    (
                                        Type::Tuple(
                                            vec![],
                                        ),
                                        s!(351..353),
                                    ),
                                    (
                                        Type::Struct(
                                            vec![],
                                        ),
                                        s!(356..358),
                                    ),
                                    (
                                        Type::Ident(
                                            "Blub",
                                        ),
                                        s!(361..365),
                                    ),
                                ],
                            ),
                            s!(351..365),
                        ),
                    },
                    s!(339..366),
                ),
            ],

            templates: vec![
                (
                    Template {
                        output_type: (None, s!(79..79)),
                        name: ("tour", s!(88..92)),
                        parameters: vec![],
                        body: TemplateBody {
                            indentation_marker: IndentationMarker::Present {
                                indentation_and_span: ("", s!(100..100)),
                            },
                            lines: vec![
                                (
                                    TemplateLine {
                                        had_comments: true,
                                        indentation: ("\t", s!(102..103)),
                                        content: vec![],
                                        newline: (
                                            TemplateLineNewline::Normal("\n"),
                                            s!(122..123)
                                        )
                                    },
                                    s!(102..123)
                                ),
                                (
                                    TemplateLine {
                                        had_comments: true,
                                        indentation: ("\t", s!(123..124)),
                                        content: vec![],
                                        newline: (
                                            TemplateLineNewline::Normal("\n"),
                                            s!(157..158)
                                        )
                                    },
                                    s!(123..158)
                                ),
                                (
                                    TemplateLine {
                                        had_comments: false,
                                        indentation: ("\t", s!(158..159)),
                                        content: vec![
                                            (
                                                TemplateContent::EscapeSequence(
                                                    TemplateContentEscapeSequence::Curly(
                                                        CurlyKind::Opening,
                                                        2,
                                                        "{{",
                                                        s!(95..97),
                                                    )
                                                ),
                                                s!(159..162)
                                            ),
                                            (TemplateContent::Static(" "), s!(162..163)),
                                            (
                                                TemplateContent::EscapeSequence(
                                                    TemplateContentEscapeSequence::Curly(
                                                        CurlyKind::Closing,
                                                        2,
                                                        "}}",
                                                        s!(95..97)
                                                    )
                                                ),
                                                s!(163..166)
                                            ),
                                            (TemplateContent::Static(" "), s!(166..167)),
                                            (
                                                TemplateContent::EscapeSequence(
                                                    TemplateContentEscapeSequence::Curly(
                                                        CurlyKind::Opening,
                                                        2,
                                                        "{{",
                                                        s!(95..97)
                                                    )
                                                ),
                                                s!(167..170)
                                            ),
                                            (TemplateContent::Static("{ "), s!(170..172)),
                                            (
                                                TemplateContent::EscapeSequence(
                                                    TemplateContentEscapeSequence::Curly(
                                                        CurlyKind::Closing,
                                                        2,
                                                        "}}",
                                                        s!(95..97)
                                                    )
                                                ),
                                                s!(172..175)
                                            ),
                                            (TemplateContent::Static("} {} "), s!(175..180))
                                        ],
                                        newline: (TemplateLineNewline::Escaped, s!(180..182))
                                    },
                                    s!(158..182)
                                ),
                                (
                                    TemplateLine {
                                        had_comments: false,
                                        indentation: ("\t  ", s!(182..185)),
                                        content: vec![(
                                            TemplateContent::Static("Some more"),
                                            s!(185..194)
                                        )],
                                        newline: (
                                            TemplateLineNewline::Normal("\n"),
                                            s!(194..195)
                                        )
                                    },
                                    s!(182..195)
                                ),
                                (
                                    TemplateLine {
                                        had_comments: false,
                                        indentation: ("\t", s!(195..196)),
                                        content: vec![(
                                            TemplateContent::Static("Second line"),
                                            s!(196..207)
                                        )],
                                        newline: (
                                            TemplateLineNewline::Normal("\n"),
                                            s!(207..208)
                                        )
                                    },
                                    s!(195..208)
                                ),
                                (
                                    TemplateLine {
                                        had_comments: false,
                                        indentation: ("\t", s!(208..209)),
                                        content: vec![(
                                            TemplateContent::Command(Box::new(Command::Assignment {
                                                variable: ("var", s!(233..236)),
                                                expression: (
                                                    Expression::Literal(Literal::String(vec![(
                                                        StringLiteralComponent::Literal("test"),
                                                        s!(240..244)
                                                    )])),
                                                    s!(239..245)
                                                )
                                            })),
                                            s!(209..247)
                                        )],
                                        newline: (
                                            TemplateLineNewline::Normal("\n"),
                                            s!(247..248)
                                        )
                                    },
                                    s!(208..248)
                                ),
                                (
                                    TemplateLine {
                                        had_comments: false,
                                        indentation: ("\t", s!(248..249)),
                                        content: vec![(
                                            TemplateContent::Command(Box::new(Command::Expression(
                                                Expression::Call {
                                                    func: (Box::new(Expression::VariableOrCall("tour2")), s!(254..259)),
                                                    arguments: vec![(
                                                        Expression::Call {
                                                            func: (Box::new(Expression::VariableOrCall("some_func")), s!(262..271)),
                                                            arguments: vec![
                                                                (
                                                                    Expression::VariableOrCall("some"),
                                                                    s!(272..276)
                                                                ),
                                                                (
                                                                    Expression::VariableOrCall("args"),
                                                                    s!(310..314)
                                                                )
                                                            ]
                                                        },
                                                        s!(262..314)
                                                    )]
                                                },
                                                s!(254..314)
                                            ))),
                                            s!(249..334)
                                        )],
                                        newline: (
                                            TemplateLineNewline::Normal("\n"),
                                            s!(334..335)
                                        )
                                    },
                                    s!(248..335)
                                )
                            ]
                        }
                    },
                    s!(79..337)
                ),
                (
                    Template {
                        output_type: (Some("html"), s!(368..372)),
                        name: ("tour2", s!(382..387)),
                        parameters: vec![
                            (("bla", s!(388..391)), (None, s!(391..391))),
                            (
                                ("bla2", s!(393..397)),
                                (
                                    Some(Type::Struct(vec![
                                        (("key", s!(461..464)), (None, s!(464..464))),
                                        (
                                            ("other_key", s!(466..475)),
                                            (Some(Type::Ident("text")), s!(477..481))
                                        ),
                                        (
                                            ("key3", s!(483..487)),
                                            (Some(Type::Array((None, s!(516..516)))), s!(489..517))
                                        )
                                    ])),
                                    s!(460..518)
                                )
                            )
                        ],
                        body: TemplateBody {
                            indentation_marker: IndentationMarker::Escaped {
                                indentation_and_span: ("\t", s!(522..523)),
                                marker_span: s!(523..525),
                                newline: ("\n", s!(525..526))
                            },
                            lines: vec![
                                (
                                    TemplateLine {
                                        had_comments: false,
                                        indentation: ("\t", s!(526..527)),
                                        content: vec![(
                                            TemplateContent::Command(Box::new(Command::Expression(
                                                Expression::VariableOrCall("bla"),
                                                s!(528..531)
                                            ))),
                                            s!(527..532)
                                        )],
                                        newline: (
                                            TemplateLineNewline::Normal("\n"),
                                            s!(532..533)
                                        )
                                    },
                                    s!(526..533)
                                ),
                                (
                                    TemplateLine {
                                        had_comments: false,
                                        indentation: ("", s!(533..533)),
                                        content: vec![],
                                        newline: (
                                            TemplateLineNewline::Normal("\n",),
                                            s!(533..534)
                                        )
                                    },
                                    s!(533..534)
                                ),
                                (
                                    TemplateLine {
                                        had_comments: false,
                                        indentation: ("\t", s!(534..535)),
                                        content: vec![
                                            (TemplateContent::Command(Box::new(Command::Expression(
                                                Expression::Literal(Literal::Template(
                                                    (Some("html"), s!(537..541)),
                                                    Box::new(TemplateBody {
                                                        indentation_marker: IndentationMarker::None,
                                                        lines: vec![(
                                                            TemplateLine {
                                                                had_comments: false,
                                                                indentation: (
                                                                    "\t\t",
                                                                    s!(543..545)
                                                                ),
                                                                content: vec![
                                                                    (
                                                                        TemplateContent::Static(
                                                                            "Hello "
                                                                        ),
                                                                        s!(545..551)
                                                                    ),
                                                                    (TemplateContent::Command(
                                                                        Box::new(Command::Expression(
                                                                            Expression::MemberAccess {
                                                                                expression: (Box::new(Expression::VariableOrCall("bla2")), s!(552..556)),
                                                                                access: (MemberAccess::Named("other_key", s!(557..566)), s!(556..566))
                                                                            },
                                                                            s!(552..566)
                                                                        ))
                                                                    ), s!(551..567)),
                                                                    (
                                                                        TemplateContent::Static("!"),
                                                                        s!(567..568)
                                                                    )
                                                                ],
                                                                newline: (TemplateLineNewline::Normal("\n"), s!(568..569))
                                                            },
                                                            s!(543..569)
                                                        )]
                                                    })
                                                )),
                                                s!(537..571)
                                            ))), s!(535..573))
                                        ],
                                        newline: (TemplateLineNewline::Normal("\n"), s!(573..574))
                                    },
                                    s!(534..574)
                                ),
                                (
                                    TemplateLine {
                                        had_comments: false,
                                        indentation: (
                                            "",
                                            s!(574..574),
                                        ),
                                        content: vec![],
                                        newline: (
                                            TemplateLineNewline::Normal(
                                                "\n",
                                            ),
                                            s!(574..575),
                                        ),
                                    },
                                    s!(574..575),
                                ),
                                (
                                    TemplateLine {
                                        had_comments: false,
                                        indentation: (
                                            "    ",
                                            s!(575..579),
                                        ),
                                        content: vec![
                                            (
                                                TemplateContent::Command(
                                                    Box::new(Command::Expression(
                                                        Expression::Select {
                                                            expr: (
                                                                Box::new(Expression::VariableOrCall(
                                                                    "bla",
                                                                )),
                                                                s!(618..621),
                                                            ),
                                                            arms: vec![
                                                                (
                                                                    (
                                                                        "whatever",
                                                                        s!(657..665),
                                                                    ),
                                                                    (
                                                                        Type::Options(
                                                                            vec![
                                                                                (
                                                                                    Type::Tuple(
                                                                                        vec![],
                                                                                    ),
                                                                                    s!(667..669),
                                                                                ),
                                                                                (
                                                                                    Type::Ident(
                                                                                        "whichever",
                                                                                    ),
                                                                                    s!(672..681),
                                                                                ),
                                                                            ],
                                                                        ),
                                                                        s!(667..681),
                                                                    ),
                                                                    (
                                                                        Expression::Literal(
                                                                            Literal::String(
                                                                                vec![],
                                                                            ),
                                                                        ),
                                                                        s!(685..687),
                                                                    ),
                                                                ),
                                                            ],
                                                        },
                                                        s!(581..694),
                                                    )),
                                                ),
                                                s!(579..708),
                                            ),
                                        ],
                                        newline: (
                                             TemplateLineNewline::Normal(
                                                "\n",
                                            ),
                                            s!(708..709),
                                        ),
                                    },
                                    s!(575..709),
                                ),
                            ]
                        }
                    },
                    s!(368..710)
                )
            ]
        }
    );
}
