//! returns: 0
//! Test suite for stack memory allocation and aliasing behavior.
//! Tests variable aliasing, mutations, and stack frame management.

record Person {
    age: i32,
    score: i32,
}

record Container {
    values: [i32; 3],
    count: i32,
}

/// Basic variable aliasing and mutation.
fn testBasicAliasing() -> i32 {
    let mut x: i32 = 10;
    let mut y: i32 = x;  // y aliases x's value

    x = 20;          // Modify x
    y += 5;       // Modify y independently

    return x + y;    // Should be 20 + 15 = 35
}

/// Struct aliasing and field mutation.
fn testStructAliasing() -> i32 {
    let mut p1: Person = Person { age: 25, score: 100 };
    let mut p2: Person = p1;     // Copy record

    p1.age = 30;             // Modify original
    p2.score = 0;            // Modify copy

    return p1.age + p1.score + p2.age + p2.score; // 30+100+25+0 = 155
}

/// Array aliasing and element mutation.
fn testArrayAliasing() -> i32 {
    let mut arr1: [i32; 3] = [1, 2, 3];
    let mut arr2: [i32; 3] = arr1;  // Copy array
    arr1[0] = 10;               // Modify original
    arr2[1] = 20;               // Modify copy
    // Arrays should be independent
    return arr1[0] + arr1[1] + arr2[0] + arr2[1]; // 10+2+1+20 = 33
}

/// Test 4: Nested record with array mutation.
fn testNestedStructArrayMutation() -> i32 {
    let mut container1: Container = Container {
        values: [1, 2, 3],
        count: 3
    };
    let mut container2: Container = container1;  // Copy entire record

    container1.values[0] = 50;              // Modify nested array in original
    container1.count = 5;                   // Modify field in original

    container2.values[2] = 60;              // Modify nested array in copy
    container2.count = 7;                   // Modify field in copy

    return container1.values[0] + container1.count +
           container2.values[2] + container2.count; // 50+5+60+7 = 122
}

/// Variable overwriting with different types/scopes.
fn testVariableOverwriting() -> i32 {
    let mut result: i32 = 0;
    let mut temp: i32 = 10;
    result = temp;      // First assignment

    temp = 20;          // Overwrite temp
    result += temp; // result = 10 + 20 = 30

    // Create new scope with same variable name
    if true {
        let mut temp: i32 = 50;   // Shadow outer temp
        result += temp; // result = 30 + 50 = 80
        temp = 60;        // Modify inner temp
        result += temp; // result = 80 + 60 = 140
    }
    result += temp;   // Should use outer temp (20)

    return result;            // 140 + 20 = 160
}

/// Array of structs with aliasing.
fn testArrayOfStructsAliasing() -> i32 {
    let mut people: [Person; 2] = [
        Person { age: 10, score: 20 },
        Person { age: 15, score: 25 }
    ];
    let mut backup: [Person; 2] = people;  // Copy array of structs

    people[0].age = 12;        // Modify original
    people[1].score = 30;      // Modify original

    backup[0].score = 22;      // Modify copy
    backup[1].age = 18;        // Modify copy

    return people[0].age + people[0].score + people[1].age + people[1].score +
           backup[0].age + backup[0].score + backup[1].age + backup[1].score;
}

/// Complex mutation chain.
fn testMutationChain() -> i32 {
    let mut a: i32 = 1;
    let mut b: i32 = 2;
    let mut c: i32 = 3;

    a = b;          // a = 2
    b = c;          // b = 3
    c = a + b;      // c = 2 + 3 = 5
    a = c - b;      // a = 5 - 3 = 2
    b = a * c;      // b = 2 * 5 = 10

    return a + b + c; // 2 + 10 + 5 = 17
}

/// Struct field reassignment with aliasing.
fn testStructFieldReassignment() -> i32 {
    let mut original: Person = Person { age: 30, score: 40 };
    let mut copied: Person = original;

    // Swap fields in original
    let mut temp: i32 = original.age;
    original.age = original.score;
    original.score = temp;

    // Different swap in copy
    temp = copied.score;
    copied.score = copied.age;
    copied.age = temp;

    return original.age + original.score + copied.age + copied.score;
    // 40+30 + 40+30 = 140
}

/// Array index mutation with aliasing.
fn testArrayIndexMutation() -> i32 {
    let mut indices: [u32; 3] = [0, 1, 2];
    let mut values: [i32; 3] = [10, 20, 30];
    let mut backup: [i32; 3] = values;

    // Use indices to modify values
    values[indices[0]] = 25;     // values[0] = 25
    values[indices[1]] = 35;     // values[1] = 35

    // Modify indices
    indices[0] = 2;
    indices[2] = 0;

    // Use new indices on backup
    backup[indices[0]] = 40;   // backup[2] = 40
    backup[indices[2]] = 45;   // backup[0] = 45

    return values[0] + values[1] + values[2] +
           backup[0] + backup[1] + backup[2];
    // 25+35+30 + 45+20+40 = 195
}

/// Multiple assignment levels.
fn testMultipleAssignmentLevels() -> i32 {
    let mut level1: Person = Person { age: 10, score: 20 };
    let mut level2: Person = level1;
    let mut level3: Person = level2;
    let mut level4: Person = level3;

    // Modify each level
    level1.age = 11;
    level2.age = 12;
    level3.age = 13;
    level4.age = 14;

    level1.score = 21;
    level2.score = 22;
    level3.score = 23;
    level4.score = 24;

    return (level1.age + level1.score) +
           (level2.age + level2.score) +
           (level3.age + level3.score) +
           (level4.age + level4.score);
    // (11+21) + (12+22) + (13+23) + (14+24) = 32+34+36+38 = 140
}

@default fn main() -> i32 {
    if (testBasicAliasing() != 35) {
        return 1; // Failure
    }
    if (testStructAliasing() != 155) {
        return 1; // Failure
    }
    if (testArrayAliasing() != 33) {
        return 1; // Failure
    }
    if (testNestedStructArrayMutation() != 122) {
        return 1; // Failure
    }
    if (testVariableOverwriting() != 160) {
        return 1; // Failure
    }
    if (testArrayOfStructsAliasing() != 152) {
        return 1; // Failure
    }
    if (testMutationChain() != 17) {
        return 1; // Failure
    }
    if (testStructFieldReassignment() != 140) {
        return 1; // Failure
    }
    if (testArrayIndexMutation() != 195) {
        return 1; // Failure
    }
    if (testMultipleAssignmentLevels() != 140) {
        return 1; // Failure
    }
    return 0; // Success
}
