/********************************************************************************
 * Copyright (c) 2025-2026 ZF Friedrichshafen AG
 *
 * This program and the accompanying materials are made available under the
 * terms of the Apache License Version 2.0 which is available at
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Contributors:
 *   Erik Verhoeven - initial API and implementation
 ********************************************************************************/

#include "includes.h"
#include "parser_test.h"
#include "../../../sdv_executables/sdv_idl_compiler/parser.h"
#include "../../../sdv_executables/sdv_idl_compiler/entities/definition_entity.cpp"
#include "../../../sdv_executables/sdv_idl_compiler/entities/struct_entity.cpp"
#include "../../../sdv_executables/sdv_idl_compiler/entities/variable_entity.h"
#include "../../../sdv_executables/sdv_idl_compiler/entities/declaration_entity.h"
#include "../../../sdv_executables/sdv_idl_compiler/entities/entity_value.h"

using CParserStructTest = CParserTest;

TEST_F(CParserStructTest, ForwardDeclaration)
{
    // struct <struct_identifier>; --> forward declaration
    EXPECT_TRUE(CParser("struct S1; struct S1 {};").Parse().Root()->Find("S1"));
    EXPECT_TRUE(CParser("struct S1 {}; struct S1;").Parse().Root()->Find("S1"));
    EXPECT_TRUE(CParser("struct S1; struct S1; struct S1; struct S1;").Parse().Root()->Find("S1"));
    EXPECT_TRUE(CParser("struct S1 {}; struct S1; struct S1; ").Parse().Root()->Find("S1"));
    EXPECT_THROW(CParser("struct S1 {}; struct S1; struct S1 {}; ").Parse(), CCompileException);
}

TEST_F(CParserStructTest, Definition)
{
    // struct <struct_identifier> {...}; --> struct definition
    EXPECT_TRUE(CParser("struct S2 {};").Parse().Root()->Find("S2"));
    EXPECT_TRUE(CParser("struct S2 { int32 i; };").Parse().Root()->Find("S2"));
    EXPECT_TRUE(CParser("struct S2 { int32 i; };").Parse().Root()->Find("S2::i"));
}

TEST_F(CParserStructTest, DefinitionWithInheritance)
{
    // struct <struct_identifier> : <base_struct,...> {...}; --> struct definition with inheritance
    EXPECT_TRUE(CParser("struct S3base {int32 i;}; struct S3 : S3base {int32 j;};").Parse().Root()->Find("S3"));
    EXPECT_TRUE(CParser("struct S3base_1 {int32 i;}; struct S3base_2 {int32 i;}; struct S3_12 : S3base_1, S3base_2 {int32 j;};").Parse().Root()->Find("S3_12"));
    EXPECT_TRUE(CParser("struct S3base_1 {}; struct S3base_2 : S3base_1 {}; struct S3_12 : S3base_2 {};").Parse().Root()->Find("S3_12"));
    EXPECT_TRUE(CParser("struct S3base_1 {}; struct S3base_2 : S3base_1 {}; struct S3_12 : S3base_1, S3base_2 {};").Parse().Root()->Find("S3_12"));
    // S3base is not defined
    EXPECT_THROW(CParser("struct S3 : S3base {};").Parse(), CCompileException);
    EXPECT_THROW(CParser("struct S3base; struct S3 : S3base {};").Parse(), CCompileException);
    // Invalid base struct
    EXPECT_THROW(CParser("const uint32_t S1 = 10; struct S2 : S1 {};").Parse(), CCompileException);
}

TEST_F(CParserStructTest, DuplicateNameThroughInheritance)
{
    EXPECT_THROW(CParser("struct S1 {const char c = 'C';}; struct S2 : S1 {const int32  c = 10;};").Parse(), CCompileException);
    EXPECT_THROW(CParser("struct S1; struct S1 {const char c = 'C';}; struct S2 : S1 {const int32  c = 10;};").Parse(), CCompileException);
    EXPECT_THROW(CParser("struct S1 {const char c = 'C';}; struct S2 : S1 {}; struct S3 : S2 {const int32  c = 10;};").Parse(), CCompileException);
}

TEST_F(CParserStructTest, DeclarationsAndTypedefs)
{
    const char szCode[] = R"code(
struct S
{
    struct S1
    {
        int32 a;
        int32 b;
        int32 c;
    };
    typedef S1 TS1;
    struct S2 : TS1
    {
        int32 d;
        int32 e;
        int32 f;
    };
    typedef S2 TS2;
    struct S3
    {
        TS1 ts1Value;
        TS2 ts2Value;
    };
    typedef S3 TS3;
    TS3 ts3Value;
    typedef TS3 TS4;
    TS4 ts4Value;
};
)code";
    CParser parser(szCode);
    parser.Parse();
    EXPECT_TRUE(parser.Root()->Find("S::S1"));
    EXPECT_TRUE(parser.Root()->Find("S::S1::a"));
    EXPECT_TRUE(parser.Root()->Find("S::S1::b"));
    EXPECT_TRUE(parser.Root()->Find("S::S1::c"));
    EXPECT_TRUE(parser.Root()->Find("S::TS1"));
    EXPECT_TRUE(parser.Root()->Find("S::TS1::a"));
    EXPECT_TRUE(parser.Root()->Find("S::TS1::b"));
    EXPECT_TRUE(parser.Root()->Find("S::TS1::c"));
    EXPECT_TRUE(parser.Root()->Find("S::S2"));
    EXPECT_TRUE(parser.Root()->Find("S::S2::a"));
    EXPECT_TRUE(parser.Root()->Find("S::S2::b"));
    EXPECT_TRUE(parser.Root()->Find("S::S2::c"));
    EXPECT_TRUE(parser.Root()->Find("S::S2::d"));
    EXPECT_TRUE(parser.Root()->Find("S::S2::e"));
    EXPECT_TRUE(parser.Root()->Find("S::S2::f"));
    EXPECT_TRUE(parser.Root()->Find("S::TS2"));
    EXPECT_TRUE(parser.Root()->Find("S::TS2::a"));
    EXPECT_TRUE(parser.Root()->Find("S::TS2::b"));
    EXPECT_TRUE(parser.Root()->Find("S::TS2::c"));
    EXPECT_TRUE(parser.Root()->Find("S::TS2::d"));
    EXPECT_TRUE(parser.Root()->Find("S::TS2::e"));
    EXPECT_TRUE(parser.Root()->Find("S::TS2::f"));
    EXPECT_TRUE(parser.Root()->Find("S::S3"));
    EXPECT_TRUE(parser.Root()->Find("S::TS3"));
    EXPECT_TRUE(parser.Root()->Find("S::ts3Value.ts1Value"));
    EXPECT_TRUE(parser.Root()->Find("S::ts3Value.ts2Value"));
    EXPECT_TRUE(parser.Root()->Find("S::ts3Value.ts1Value.a"));
    EXPECT_TRUE(parser.Root()->Find("S::ts3Value.ts1Value.b"));
    EXPECT_TRUE(parser.Root()->Find("S::ts3Value.ts1Value.c"));
    EXPECT_TRUE(parser.Root()->Find("S::ts3Value.ts2Value.a"));
    EXPECT_TRUE(parser.Root()->Find("S::ts3Value.ts2Value.b"));
    EXPECT_TRUE(parser.Root()->Find("S::ts3Value.ts2Value.c"));
    EXPECT_TRUE(parser.Root()->Find("S::ts3Value.ts2Value.d"));
    EXPECT_TRUE(parser.Root()->Find("S::ts3Value.ts2Value.e"));
    EXPECT_TRUE(parser.Root()->Find("S::ts3Value.ts2Value.f"));
    EXPECT_TRUE(parser.Root()->Find("S::TS4"));
    EXPECT_TRUE(parser.Root()->Find("S::ts4Value.ts1Value"));
    EXPECT_TRUE(parser.Root()->Find("S::ts4Value.ts2Value"));
    EXPECT_TRUE(parser.Root()->Find("S::ts4Value.ts1Value.a"));
    EXPECT_TRUE(parser.Root()->Find("S::ts4Value.ts1Value.b"));
    EXPECT_TRUE(parser.Root()->Find("S::ts4Value.ts1Value.c"));
    EXPECT_TRUE(parser.Root()->Find("S::ts4Value.ts2Value.a"));
    EXPECT_TRUE(parser.Root()->Find("S::ts4Value.ts2Value.b"));
    EXPECT_TRUE(parser.Root()->Find("S::ts4Value.ts2Value.c"));
    EXPECT_TRUE(parser.Root()->Find("S::ts4Value.ts2Value.d"));
    EXPECT_TRUE(parser.Root()->Find("S::ts4Value.ts2Value.e"));
    EXPECT_TRUE(parser.Root()->Find("S::ts4Value.ts2Value.f"));
}

TEST_F(CParserStructTest, VariableDeclaration)
{
    // <struct_identifier> <decl_identifier>; --> struct variable declaration
    EXPECT_TRUE(CParser("struct S{struct S4 {int32 i;}; S4 s4Value;};").Parse().Root()->Find("S::s4Value"));
    EXPECT_TRUE(CParser("struct S{struct S4 {int32 i;}; S4 s4Value;};").Parse().Root()->Find("S::s4Value.i"));
    EXPECT_TRUE(CParser("struct S{struct S4 {int32 i;}; typedef S4 S5; S5 s5Value;};").Parse().Root()->Find("S::s5Value.i"));
    EXPECT_TRUE(CParser("struct S{struct S4 {struct S5{int32 i;} s5Value;}; typedef S4 S6; S6 s6Value;};").Parse().Root()->Find("S::s6Value.s5Value.i"));
    EXPECT_TRUE(CParser("struct S{struct S4 {struct S5{int32 i;} s5Value;}; typedef S4 S6; S6 s6Value;}; const S sValue = {{{10}}};").Parse().Root()->Find("sValue.s6Value.s5Value.i"));
    // struct <struct_identifier> <decl_identifier>; --> struct variable declaration
    EXPECT_TRUE(CParser("struct S{struct S6 {int32 i;}; struct S6 s6Value;};").Parse().Root()->Find("S::s6Value"));
}

TEST_F(CParserStructTest, VarDeclarationAndAssignment)
{
    // <struct_identifier> <decl_identifier> = {...}; --> struct variable declaration and assignment
    EXPECT_TRUE(CParser("struct S{struct S5 {int32 i;}; S5 s5Value = {10};};").Parse().Root()->Find("S::s5Value"));
    EXPECT_TRUE(CParser("struct S{struct S5b {int32 i = 11;}; S5b s5bValue = {10};};").Parse().Root()->Find("S::s5bValue"));
    // struct <struct_identifier> <decl_identifier> = {...}; --> struct variable declaration and assignment
    EXPECT_TRUE(CParser("struct S{struct S7 {int32 i;}; struct S7 s7Value = {10};};").Parse().Root()->Find("S::s7Value"));
}

TEST_F(CParserStructTest, VarDeclarationAndAssignmentOfStructDecl)
{
    EXPECT_EQ(CParser("struct S1{int32 i;}; struct S2{ S1 sValue1 = {10}; S1 sValue2 = sValue1; };").Parse().Root()->FindValueVariant("S2::sValue2.i").Get<int32_t>(), 10);
    EXPECT_EQ(CParser("struct S1{int32 i[2];}; struct S2{ S1 sValue1 = {{10, 20}}; S1 sValue2 = sValue1; };").Parse().Root()->FindValueVariant("S2::sValue2.i[1]").Get<int32_t>(), 20);
    EXPECT_EQ(CParser("struct S1{int32 i[2][2];}; struct S2{ S1 sValue1 = {{{10, 20}, {30, 40}}}; S1 sValue2 = sValue1; };").Parse().Root()->FindValueVariant("S2::sValue2.i[1][1]").Get<int32_t>(), 40);
    EXPECT_EQ(CParser("struct S1{typedef int32 ti[2]; ti i[2];}; struct S2{ S1 sValue1 = {{{10, 20}, {30, 40}}}; S1 sValue2 = sValue1; };").Parse().Root()->FindValueVariant("S2::sValue2.i[1][1]").Get<int32_t>(), 40);
    EXPECT_EQ(CParser("typedef struct tagS1 {int32 i;} S1; struct S2{ S1 sValue1 = {10}; S1 sValue2 = sValue1; };").Parse().Root()->FindValueVariant("S2::sValue2.i").Get<int32_t>(), 10);
    EXPECT_EQ(CParser("typedef struct tagS1 {int32 i;} S1; struct S2{ S1 sValue1[2] = {{10}, {20}}; S1 sValue2 = sValue1[1]; };").Parse().Root()->FindValueVariant("S2::sValue2.i").Get<int32_t>(), 20);
    EXPECT_EQ(CParser("typedef struct tagS1 {int32 i;} S1; const int32 index = 2; struct S2{ S1 sValue1[index] = {{10}, {20}}; S1 sValue2 = sValue1[1]; };").Parse().Root()->FindValueVariant("S2::sValue2.i").Get<int32_t>(), 20);
    EXPECT_EQ(CParser("typedef struct tagS1 {int32 i;} S1; struct S2{ S1 sValue1[2] = {{10}, {20}};}; struct S3{S1 sValue2 = S2.sValue1[1]; };").Parse().Root()->FindValueVariant("S3::sValue2.i").Get<int32_t>(), 20);
}

TEST_F(CParserStructTest, DefinitionAndVariableDeclaration)
{
    // struct <struct_identifier> {...} <decl_identifier>; --> struct definition and variable declaration
    EXPECT_TRUE(CParser("struct S{struct S8 {int32 i;} s8Value;};").Parse().Root()->Find("S::s8Value"));
}

TEST_F(CParserStructTest, DefinitionWithInheritanceAndVariableDeclaration)
{
    // struct <struct_identifier> : <base_struct,...> {...} <decl_identifier>;  --> struct definition with inheritance and variable declaration
    EXPECT_TRUE(CParser("struct S{struct S9base {int32 i;}; struct S9 : S9base {int32  j;} s9Value;};").Parse().Root()->Find("S::s9Value"));
}

TEST_F(CParserStructTest, DefinitionAndVariableDeclarationAndAssignment)
{
    // struct <struct_identifier> {...} <decl_identifier> = {...};  --> struct definition, variable declaration and assignment
    EXPECT_TRUE(CParser("struct S{struct S10 {int32 i;} s10Value = {10};};").Parse().Root()->Find("S::s10Value"));
}

TEST_F(CParserStructTest, DefinitionWithInheritanceAndVariableDeclarationAndAssignment)
{
    // struct <struct_identifier> : <base_struct,...> {...} <decl_identifier> = {...}; --> struct definition with inheritance, variable declaration and assignment
    EXPECT_TRUE(CParser("struct S{struct S11base {int32 i;}; struct S11 : S11base {int32  j;} s11Value = {{10}, 10};};").Parse().Root()->Find("S::s11Value"));
    EXPECT_TRUE(CParser("struct S{struct S11base {int32 i;}; struct S11 : S11base {} s11Value = {{10}};};").Parse().Root()->Find("S::s11Value"));
}

TEST_F(CParserStructTest, UnnamedDefinitionAndVariableDeclaration)
{
    // struct {...} <decl_identifier>; --> unnamed struct definition and variable declaration
    // NOTE 11.04.2025: Not allowed due to incompatibility in C++ standard
    EXPECT_THROW(CParser("struct S{struct {int32 i;} s12Value;};").Parse(), CCompileException);
}

TEST_F(CParserStructTest, UnnamedDefinitionWithInheritanceAndVariableDeclaration)
{
    // struct : <base_struct,...> {...} <decl_identifier>; --> unnamed struct definition with inheritance and variable declaration
    // NOTE 11.04.2025: Not allowed due to incompatibility in C++ standard
    EXPECT_THROW(CParser("struct S{struct S13base {int32 i;}; struct : S13base {int32 j;} s13Value;};").Parse(), CCompileException);
}

TEST_F(CParserStructTest, UnnamedDefinitionAndVariableDeclarationAndAssignment)
{
    // struct {...} <decl_identifier> = {...}; --> unnamed struct definition, variable declaration and assignment
    // NOTE 11.04.2025: Not allowed due to incompatibility in C++ standard
    EXPECT_THROW(CParser("struct S{struct {int32 i;} s14Value = {10};};").Parse(), CCompileException);
}

TEST_F(CParserStructTest, UnnamedDefinitionWithInheritanceAndVariableDeclarationAndAssignment)
{
    // struct : <base_struct,...> {...} <decl_identifier> = {...};  --> unnamed struct definition with inheritance, variable declaration and assignment
    // NOTE 11.04.2025: Not allowed due to incompatibility in C++ standard
    EXPECT_THROW(CParser("struct S{struct S15base {int32 i;}; struct : S15base {int32 j;} s15Value = {{10}, 10};};").Parse(), CCompileException);
}

TEST_F(CParserStructTest, ComplexCombinationWithStructTypedefMultiDimmensionalArrayDeclarations)
{
    const char szCode[] = R"code(
        struct S
        {
            const int32 a = 2;
            typedef int32 intarray[a];
            typedef intarray initintarray[3][1];
            initintarray rgarray[4] = {{{{1,2}}, {{3,4}}, {{5,6}}},
                {{{7,8}},{{9,10}}, {{a,b}}},
                {{{13,14}}, {{15,16}}, {{17,18}}},
                {{{19,20}},{{21,22}}, {{23,24}}} };
            const int32 b = 4;
        };
    )code";

    CParser parser(szCode);
    EXPECT_NO_THROW(parser.Parse());
    CEntityPtr ptrVar = parser.Root()->Find("S::rgarray");
    ASSERT_TRUE(ptrVar);
    CDeclarationEntity* pVar = ptrVar->Get<CDeclarationEntity>();
    ASSERT_NE(pVar, nullptr);
    CValueNodePtr ptrVal = ptrVar->ValueRef();
    ASSERT_TRUE(ptrVal);
    CArrayValueNode* pInitIntArrayVal = ptrVal->Get<CArrayValueNode>();
    ASSERT_NE(pInitIntArrayVal, nullptr);
    EXPECT_EQ(pInitIntArrayVal->GetSize(), 4);
    CValueNodePtr ptrIntArrayVal = (*pInitIntArrayVal)[3];
    ASSERT_TRUE(ptrIntArrayVal);
    CArrayValueNode* pIntArrayVal = ptrIntArrayVal->Get<CArrayValueNode>();
    ASSERT_NE(pIntArrayVal, nullptr);
    EXPECT_EQ(pIntArrayVal->GetSize(), 3);
    CValueNodePtr ptrIntArrayVal_2 = (*pIntArrayVal)[2];
    ASSERT_TRUE(ptrIntArrayVal_2);
    CArrayValueNode* pIntArrayVal_2 = ptrIntArrayVal_2->Get<CArrayValueNode>();
    ASSERT_NE(pIntArrayVal_2, nullptr);
    EXPECT_EQ(pIntArrayVal_2->GetSize(), 1);
    CValueNodePtr ptrIntArrayVal_3 = (*pIntArrayVal_2)[0];
    ASSERT_TRUE(ptrIntArrayVal_3);
    CArrayValueNode* pIntArrayVal_3 = ptrIntArrayVal_3->Get<CArrayValueNode>();
    ASSERT_NE(pIntArrayVal_3, nullptr);
    EXPECT_EQ(pIntArrayVal_3->GetSize(), 2);
    CValueNodePtr ptrIntVal = (*pIntArrayVal_3)[1];
    ASSERT_TRUE(ptrIntVal);
    CSimpleTypeValueNode* pIntVal = ptrIntVal->Get<CSimpleTypeValueNode>();
    ASSERT_NE(pIntVal, nullptr);
    EXPECT_EQ(pIntVal->Variant().Get<int32_t>(), 24);
}

TEST_F(CParserStructTest, StringAssignmentInStruct)
{
    // Tests bug fix: #380904
    const char szCode[] = R"code(
    struct SStringTest
    {
        string ssVal = "hello";
        u8string ss8Val = u8"hello";
    };
    )code";

    CParser parser(szCode);
    EXPECT_NO_THROW(parser.Parse());
}

