// Feature examples for homepage/docs

// --- Control Flow: if ---
const ControlIfProps = struct { is_admin: bool };
pub fn ControlIf(
    allocator: zx.Allocator,
    props: ControlIfProps,
) zx.Component {
    return (
        <div @{allocator}>
            {if (props.is_admin) (
                <span>Admin</span>
            ) else (
                <span>Member</span>
            )}
        </div>
    );
}

// --- Control Flow: if optional capture ---
pub fn ControlIfOptional(allocator: zx.Allocator) zx.Component {
    const maybe_name: ?[]const u8 = "Zig";
    return (
        <div @{allocator}>
            {if (maybe_name) |name| (<span>{name}</span>)}
        </div>
    );
}

// --- Control Flow: if error capture ---
pub fn ControlIfError(allocator: zx.Allocator) zx.Component {
    const parsed =
        std.fmt.parseInt(u32, "42", 10);

    return (
        <div @{allocator}>
            {if (parsed) |value| (
                <span>{value}</span>
            ) else |err| (
                <span>{@errorName(err)}</span>
            )}
        </div>
    );
}

// --- Control Flow: switch ---
const Role = enum { admin, member, guest };
const ControlSwitchProps = struct { role: Role };
pub fn ControlSwitch(allocator: zx.Allocator, props: ControlSwitchProps) zx.Component {
    return (
        <div @{allocator}>
            {switch (props.role) {
                .admin => (<span>Admin</span>),
                .member => (<span>Member</span>),
                else => (<span>Guest</span>),
            }}
        </div>
    );
}

// --- Control Flow: for ---
const ControlForProps = struct { items: []const []const u8 };
pub fn ControlFor(allocator: zx.Allocator, props: ControlForProps) zx.Component {
    return (
        <ul @{allocator}>
            {for (props.items) |item| (<li>{item}</li>)}
        </ul>
    );
}

// --- Control Flow: while ---
pub fn ControlWhile(allocator: zx.Allocator) zx.Component {
    var i: usize = 0;
    return (
        <ul @{allocator}>
            {while (i < 3) : (i += 1) (<li>Item {i + 1}</li>)}
        </ul>
    );
}

// --- Control Flow: while optional capture ---
pub fn ControlWhileOptional(allocator: zx.Allocator) zx.Component {
    var maybe: ?u32 = 1;
    return (
        <ul @{allocator}>
            {while (maybe) |value| : (maybe = if (value < 3) value + 1 else null) (
                <li>{value}</li>
            )}
        </ul>
    );
}

// --- Control Flow: while error capture ---
pub fn ControlWhileError(allocator: zx.Allocator) zx.Component {
    var first: bool = true;
    return (
        <div @{allocator}>
            {while (parseOnce(&first)) |value| (
                <span>{value}</span>
            ) else |err| (
                <span>{@errorName(err)}</span>
            )}
        </div>
    );
}

fn parseOnce(first: *bool) !u32 {
    if (first.*) {
        first.* = false;
        return 42;
    }
    return error.Done;
}

// --- Caching: component ---
pub fn CacheComponent(allocator: zx.Allocator) zx.Component {
    return (<Expensive @{allocator} @caching="10s" />);
}

fn Expensive(allocator: zx.Allocator) zx.Component {
    // std.Thread.sleep(std.time.ns_per_s * 3);
    return (<div @{allocator}></div>);
}
// --- Caching: page ---
pub fn Caching__Page(
    ctx: zx.PageContext,
) zx.Component {
    // std.Thread.sleep(std.time.ns_per_s * 3);
    return (
        <div @allocator={ctx.arena}>
            <h1>Expensive Page</h1>
            <p>I take too long to load.</p>
        </div>
    );
}

pub const options = zx.PageOptions{
    .caching = .{ .seconds = 300 },
};

// --- File System Routing: page ---
pub fn Routing__Page(
    ctx: zx.PageContext,
) zx.Component {
    return (
        <div @allocator={ctx.arena}>
            <h1>Home</h1>
        </div>
    );
}

// --- File System Routing: layout ---
pub fn Layout(
    ctx: zx.LayoutContext,
    children: zx.Component,
) zx.Component {
    return (
        <html @allocator={ctx.arena}>
            <body>
                {children}
            </body>
        </html>
    );
}

// --- Component: basics ---
const ButtonProps = struct { label: []const u8 };
pub fn Button(
    ctx: *zx.ComponentCtx(ButtonProps),
) zx.Component {
    return (
        <button @allocator={ctx.allocator}>
            {ctx.props.label}
        </button>
    );
}

// --- Component: fragment ---
pub fn Fragment(
    allocator: zx.Allocator,
) zx.Component {
    return (
        <fragment @{allocator}>
            <span>One</span>
            <>
                <p>Two</p><p>Three</p>
            </>
        </fragment>
    );
}

// --- Component: props ---
pub fn SpreadProps(
    allocator: zx.Allocator,
) zx.Component {
    const attrs =
        .{ .class = "btn", .id = "cta" };
    const class = "primary";
    return (
        <section @{allocator}>
            <button {..attrs}>Spreading</button>
            <button {class}>Shorthand</button>
        </section>
    );
}

// --- Component: attr ---
pub fn DynamicAttr(
    allocator: zx.Allocator,
) zx.Component {
    const is_active = true;
    const class = if (is_active) "active" else "idle";
    const color = if (is_active) "green" else "red";
    return (
        <section @{allocator}>
            <button class={class}>Go</button>
            <button style=`color: {color};`>
                Template String
            </button>
        </section>
    );
}

// --- Dynamic Path ---
pub fn Page(ctx: zx.PageContext) zx.Component {
    const id = ctx.request.params.get("id");
    return (
        <section @allocator={ctx.arena}>
            <h1>User {id}</h1>
        </section>
    );
}

// --- API Route ---
pub fn PUT(ctx: zx.RouteContext) !void {
    try ctx.response.json(.{ .status = "ok" });
}

pub fn POST(ctx: zx.RouteContext) !void {
    const Data = struct { id: u32 };
    const data =
        try ctx.request.json(Data, .{});

    try ctx.response.json(.{
        .id = data.?.id,
        .created = true,
    });
}

// --- WebSocket ---
pub fn GET(ctx: zx.RouteContext) !void {
    try ctx.socket.upgrade({});
}

pub fn Socket(ctx: zx.SocketContext) !void {
    try ctx.socket.write(
        try ctx.fmt("{s}", .{ctx.message}),
    );
}

pub fn SocketOpen(ctx: zx.SocketOpenContext) !void {
    try ctx.socket.write("Opened!");
}

// --- Client-side Rendering ---
pub fn Client(allocator: zx.Allocator) zx.Component {
    return (<Counter @{allocator} @rendering={.client} />);
}
pub fn Counter(ctx: *zx.ComponentCtx(void)) zx.Component {
    const count = ctx.state(i32, 0);
    return (
        <div @allocator={ctx.allocator} class="counter">
            <button onclick={ctx.bind(&increment)}>
                Click Me: {count.get()}
            </button>
        </div>
    );
}
fn increment(e: *zx.client.Event.Stateful) void {
    const count = e.state(i32);
    count.set(count.get() + 1);
}

// --- Imports ---
pub fn RenderTest(allocator: zx.Allocator) zx.Component {
    return (
        <div @{allocator}>
            <ControlIf is_admin={true} />
            <ControlIfOptional />
            <ControlIfError />
            <ControlSwitch role={Role.member} />
            <ControlFor items={&.{"One", "Two", "Three"}} />
            <ControlWhile />
            <ControlWhileOptional />
            <ControlWhileError />
            <CacheComponent />
            <Fragment />
            <SpreadProps />
            <DynamicAttr />
            <Client />
        </div>
    );
}

const zx = @import("zx");
const std = @import("std");
