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,
    },
    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 {
            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!(339..343)),
                        name: ("tour2", s!(353..358)),
                        parameters: vec![
                            (("bla", s!(359..362)), (None, s!(362..362))),
                            (
                                ("bla2", s!(364..368)),
                                (
                                    Some(Type::Struct(vec![
                                        (("key", s!(432..435)), (None, s!(435..435))),
                                        (
                                            ("other_key", s!(437..446)),
                                            (Some(Type::Base("text")), s!(448..452))
                                        ),
                                        (
                                            ("key3", s!(454..458)),
                                            (Some(Type::Array((None, s!(487..487)))), s!(460..488))
                                        )
                                    ])),
                                    s!(431..489)
                                )
                            )
                        ],
                        body: TemplateBody {
                            indentation_marker: IndentationMarker::Escaped {
                                indentation_and_span: ("\t", s!(493..494)),
                                marker_span: s!(494..496),
                                newline: ("\n", s!(496..497))
                            },
                            lines: vec![
                                (
                                    TemplateLine {
                                        had_comments: false,
                                        indentation: ("\t", s!(497..498)),
                                        content: vec![(
                                            TemplateContent::Command(Box::new(Command::Expression(
                                                Expression::VariableOrCall("bla"),
                                                s!(499..502)
                                            ))),
                                            s!(498..503)
                                        )],
                                        newline: (
                                            TemplateLineNewline::Normal("\n"),
                                            s!(503..504)
                                        )
                                    },
                                    s!(497..504)
                                ),
                                (
                                    TemplateLine {
                                        had_comments: false,
                                        indentation: ("", s!(504..504)),
                                        content: vec![],
                                        newline: (
                                            TemplateLineNewline::Normal("\n",),
                                            s!(504..505)
                                        )
                                    },
                                    s!(504..505)
                                ),
                                (
                                    TemplateLine {
                                        had_comments: false,
                                        indentation: ("\t", s!(505..506)),
                                        content: vec![
                                            (TemplateContent::Command(Box::new(Command::Expression(
                                                Expression::Literal(Literal::Template(
                                                    (Some("html"), s!(508..512)),
                                                    Box::new(TemplateBody {
                                                        indentation_marker: IndentationMarker::None,
                                                        lines: vec![(
                                                            TemplateLine {
                                                                had_comments: false,
                                                                indentation: (
                                                                    "\t\t",
                                                                    s!(514..516)
                                                                ),
                                                                content: vec![
                                                                    (
                                                                        TemplateContent::Static(
                                                                            "Hello "
                                                                        ),
                                                                        s!(516..522)
                                                                    ),
                                                                    (TemplateContent::Command(
                                                                        Box::new(Command::Expression(
                                                                            Expression::MemberAccess {
                                                                                expression: (Box::new(Expression::VariableOrCall("bla2")), s!(523..527)),
                                                                                access: (MemberAccess::Named("other_key", s!(528..537)), s!(527..537))
                                                                            },
                                                                            s!(523..537)
                                                                        ))
                                                                    ), s!(522..538)),
                                                                    (
                                                                        TemplateContent::Static("!"),
                                                                        s!(538..539)
                                                                    )
                                                                ],
                                                                newline: (TemplateLineNewline::Normal("\n"), s!(539..540))
                                                            },
                                                            s!(514..540)
                                                        )]
                                                    })
                                                )),
                                                s!(508..542)
                                            ))), s!(506..544))
                                        ],
                                        newline: (TemplateLineNewline::Normal("\n"), s!(544..545))
                                    },
                                    s!(505..545)
                                )
                            ]
                        }
                    },
                    s!(339..546)
                )
            ]
        }
    );
}
