// Match expression with both `null` arms and concrete struct value arms
// produces an optional type (?T) and correctly wraps non-null values.

#import "modules/std.sx";

HAlignment :: enum { leading; center; trailing; }
VAlignment :: enum { top; center; bottom; }
Alignment :: struct { h: HAlignment; v: VAlignment; }

ALIGN_CENTER          :: Alignment.{ h = .center,   v = .center };
ALIGN_TOP             :: Alignment.{ h = .center,   v = .top };
ALIGN_BOTTOM          :: Alignment.{ h = .center,   v = .bottom };
ALIGN_LEADING         :: Alignment.{ h = .leading,  v = .center };
ALIGN_TRAILING        :: Alignment.{ h = .trailing, v = .center };
ALIGN_TOP_LEADING     :: Alignment.{ h = .leading,  v = .top };
ALIGN_TOP_TRAILING    :: Alignment.{ h = .trailing, v = .top };
ALIGN_BOTTOM_LEADING  :: Alignment.{ h = .leading,  v = .bottom };
ALIGN_BOTTOM_TRAILING :: Alignment.{ h = .trailing, v = .bottom };

Zone :: enum {
    floating;
    fill;
    center;
    top;
    bottom;
    left;
    right;
    top_left;
    top_right;
    bottom_left;
    bottom_right;
}

// Match expression as implicit return with mixed null/concrete arms
zone_to_alignment :: (zone: Zone) -> ?Alignment {
    if zone == {
        case .floating:     null;
        case .fill:         ALIGN_CENTER;
        case .center:       ALIGN_CENTER;
        case .top:          ALIGN_TOP;
        case .bottom:       ALIGN_BOTTOM;
        case .left:         ALIGN_LEADING;
        case .right:        ALIGN_TRAILING;
        case .top_left:     ALIGN_TOP_LEADING;
        case .top_right:    ALIGN_TOP_TRAILING;
        case .bottom_left:  ALIGN_BOTTOM_LEADING;
        case .bottom_right: ALIGN_BOTTOM_TRAILING;
    }
}

// Side-effect match inside a function returning bool — must NOT be
// affected by optional inference (no null arms here)
NodeType :: enum { rect; text; image; }
process_node :: (t: NodeType) -> bool {
    if t == {
        case .rect: { out("rect\n"); }
        case .text: { out("text\n"); }
        case .image: { out("image\n"); }
    }
    true
}

main :: () -> void {
    // Test null arm
    r0 := zone_to_alignment(.floating);
    if a := r0 { print("BUG: floating should be null, got h={}\n", xx a.h); }
    else { out("ok: floating is null\n"); }

    // Test concrete arms
    r1 := zone_to_alignment(.left);
    if a := r1 { print("ok: left h={}\n", xx a.h); }
    else { out("BUG: left returned null\n"); }

    r2 := zone_to_alignment(.center);
    if a := r2 { print("ok: center h={}\n", xx a.h); }
    else { out("BUG: center returned null\n"); }

    r3 := zone_to_alignment(.top_right);
    if a := r3 { print("ok: top_right h={} v={}\n", xx a.h, xx a.v); }
    else { out("BUG: top_right returned null\n"); }

    // Test side-effect match (no null arms) still works
    process_node(.rect);
    process_node(.text);
}
