-- Copyright (c) Microsoft Corporation.
-- Licensed under the PostgreSQL License.

-- Tests: df.join / df.join3 return a proper JSON array of objects, not an array of
-- escaped JSON strings (double-encoding bug regression test).
SET SESSION AUTHORIZATION df_e2e_user;

-- === Test 1: df.join (2-branch) result is a JSON array of objects ===

CREATE TEMP TABLE _t_join2 (instance_id TEXT);
INSERT INTO _t_join2 SELECT df.start(
    'SELECT 1 AS a' & 'SELECT 2 AS b',
    'test-join2-result-shape'
);

DO $$
DECLARE
    inst_id  TEXT;
    status   TEXT;
    raw_res  JSONB;
    elem0    JSONB;
    elem1    JSONB;
BEGIN
    SELECT instance_id INTO inst_id FROM _t_join2;
    SELECT df.await_instance(inst_id) INTO status;

    IF status != 'completed' THEN
        RAISE EXCEPTION 'TEST FAILED [join2-shape]: status = %', status;
    END IF;

    -- df.result returns the root node result as text; cast to JSONB to navigate it
    raw_res := (df.result(inst_id))::jsonb;

    -- Must be a JSON array
    IF jsonb_typeof(raw_res) != 'array' THEN
        RAISE EXCEPTION 'TEST FAILED [join2-shape]: expected array, got % — raw=%',
            jsonb_typeof(raw_res), raw_res;
    END IF;

    -- Array must have 2 elements
    IF jsonb_array_length(raw_res) != 2 THEN
        RAISE EXCEPTION 'TEST FAILED [join2-shape]: expected 2 elements, got % — raw=%',
            jsonb_array_length(raw_res), raw_res;
    END IF;

    -- Each element must be an object (not a string i.e. not double-encoded)
    elem0 := raw_res->0;
    elem1 := raw_res->1;

    IF jsonb_typeof(elem0) != 'object' THEN
        RAISE EXCEPTION 'TEST FAILED [join2-shape]: element 0 is %, expected object — raw=%',
            jsonb_typeof(elem0), raw_res;
    END IF;

    IF jsonb_typeof(elem1) != 'object' THEN
        RAISE EXCEPTION 'TEST FAILED [join2-shape]: element 1 is %, expected object — raw=%',
            jsonb_typeof(elem1), raw_res;
    END IF;

    -- Verify actual content (guards against regression producing empty objects)
    IF (elem0->>'a')::int != 1 THEN
        RAISE EXCEPTION 'TEST FAILED [join2-shape]: element 0.a expected 1, got % — raw=%',
            elem0->>'a', raw_res;
    END IF;

    IF (elem1->>'b')::int != 2 THEN
        RAISE EXCEPTION 'TEST FAILED [join2-shape]: element 1.b expected 2, got % — raw=%',
            elem1->>'b', raw_res;
    END IF;

    RAISE NOTICE 'PASSED: df.join result is a JSON array of objects';
END $$;

DROP TABLE _t_join2;

-- === Test 2: df.join3 (3-branch) result is a JSON array of objects ===

CREATE TEMP TABLE _t_join3 (instance_id TEXT);
INSERT INTO _t_join3 SELECT df.start(
    df.join3('SELECT 10 AS x', 'SELECT 20 AS y', 'SELECT 30 AS z'),
    'test-join3-result-shape'
);

DO $$
DECLARE
    inst_id  TEXT;
    status   TEXT;
    raw_res  JSONB;
    elem0    JSONB;
    elem1    JSONB;
    elem2    JSONB;
BEGIN
    SELECT instance_id INTO inst_id FROM _t_join3;
    SELECT df.await_instance(inst_id) INTO status;

    IF status != 'completed' THEN
        RAISE EXCEPTION 'TEST FAILED [join3-shape]: status = %', status;
    END IF;

    raw_res := (df.result(inst_id))::jsonb;

    -- Must be a JSON array
    IF jsonb_typeof(raw_res) != 'array' THEN
        RAISE EXCEPTION 'TEST FAILED [join3-shape]: expected array, got % — raw=%',
            jsonb_typeof(raw_res), raw_res;
    END IF;

    -- Array must have 3 elements
    IF jsonb_array_length(raw_res) != 3 THEN
        RAISE EXCEPTION 'TEST FAILED [join3-shape]: expected 3 elements, got % — raw=%',
            jsonb_array_length(raw_res), raw_res;
    END IF;

    -- Each element must be an object (not a string)
    elem0 := raw_res->0;
    elem1 := raw_res->1;
    elem2 := raw_res->2;

    IF jsonb_typeof(elem0) != 'object' THEN
        RAISE EXCEPTION 'TEST FAILED [join3-shape]: element 0 is %, expected object — raw=%',
            jsonb_typeof(elem0), raw_res;
    END IF;

    IF jsonb_typeof(elem1) != 'object' THEN
        RAISE EXCEPTION 'TEST FAILED [join3-shape]: element 1 is %, expected object — raw=%',
            jsonb_typeof(elem1), raw_res;
    END IF;

    IF jsonb_typeof(elem2) != 'object' THEN
        RAISE EXCEPTION 'TEST FAILED [join3-shape]: element 2 is %, expected object — raw=%',
            jsonb_typeof(elem2), raw_res;
    END IF;

    -- Verify actual content
    IF (elem0->>'x')::int != 10 OR (elem1->>'y')::int != 20 OR (elem2->>'z')::int != 30 THEN
        RAISE EXCEPTION 'TEST FAILED [join3-shape]: values mismatch — raw=%', raw_res;
    END IF;

    RAISE NOTICE 'PASSED: df.join3 result is a JSON array of objects';
END $$;

DROP TABLE _t_join3;

-- === Test 3: nested join — (a & b) & c — inner array must nest inside outer ===

CREATE TEMP TABLE _t_nested (instance_id TEXT);
INSERT INTO _t_nested SELECT df.start(
    ('SELECT 1 AS a' & 'SELECT 2 AS b') & 'SELECT 3 AS c',
    'test-join-nested-shape'
);

DO $$
DECLARE
    inst_id  TEXT;
    status   TEXT;
    raw_res  JSONB;
    inner_arr JSONB;
    outer_c  JSONB;
BEGIN
    SELECT instance_id INTO inst_id FROM _t_nested;
    SELECT df.await_instance(inst_id) INTO status;

    IF status != 'completed' THEN
        RAISE EXCEPTION 'TEST FAILED [join-nested-shape]: status = %', status;
    END IF;

    raw_res := (df.result(inst_id))::jsonb;

    -- Outer must be a 2-element array: [ [inner_a, inner_b], c_obj ]
    IF jsonb_typeof(raw_res) != 'array' OR jsonb_array_length(raw_res) != 2 THEN
        RAISE EXCEPTION 'TEST FAILED [join-nested-shape]: expected 2-element array, got % len=% — raw=%',
            jsonb_typeof(raw_res), jsonb_array_length(raw_res), raw_res;
    END IF;

    -- First element is the inner join result: must itself be an array, not a string
    inner_arr := raw_res->0;
    IF jsonb_typeof(inner_arr) != 'array' THEN
        RAISE EXCEPTION 'TEST FAILED [join-nested-shape]: inner element type is %, expected array (double-encoding regression) — raw=%',
            jsonb_typeof(inner_arr), raw_res;
    END IF;

    IF jsonb_array_length(inner_arr) != 2 THEN
        RAISE EXCEPTION 'TEST FAILED [join-nested-shape]: inner array length expected 2, got % — raw=%',
            jsonb_array_length(inner_arr), raw_res;
    END IF;

    IF (inner_arr->0->>'a')::int != 1 OR (inner_arr->1->>'b')::int != 2 THEN
        RAISE EXCEPTION 'TEST FAILED [join-nested-shape]: inner values mismatch — raw=%', raw_res;
    END IF;

    -- Second element is the c branch result (an object)
    outer_c := raw_res->1;
    IF jsonb_typeof(outer_c) != 'object' OR (outer_c->>'c')::int != 3 THEN
        RAISE EXCEPTION 'TEST FAILED [join-nested-shape]: outer.c element wrong — raw=%', raw_res;
    END IF;

    RAISE NOTICE 'PASSED: nested join result preserves array nesting (no double-encoding)';
END $$;

DROP TABLE _t_nested;

RESET SESSION AUTHORIZATION;
SELECT 'TEST PASSED' AS result;
