pub const File = struct {
    filename: []const u8,
    code: []const u8,
    // Computed fields (set during processing)
    highlighted: []const u8 = "",
    radio_id: []const u8 = "",
    content_id: []const u8 = "",
    is_first: bool = false,
};

pub const ExampleBlockProps = struct {
    id: []const u8,
    files: []const File = &.{},
    // Legacy single-file support (used if files is empty)
    zx_code: []const u8 = "",
    zig_code: []const u8 = "",
    html_code: []const u8,
    filename: []const u8 = "page.zx",
};

pub fn ExampleBlock(allocator: zx.Allocator, props: ExampleBlockProps) zx.Component {
    // Immediately dupe the files array to avoid stack lifetime issues
    // The props.files slice points to stack memory that may be cleaned up
    const input_files: []const File = if (props.files.len > 0) blk: {
        const duped = allocator.alloc(File, props.files.len) catch unreachable;
        for (props.files, 0..) |file, i| {
            duped[i] = .{
                .filename = allocator.dupe(u8, file.filename) catch unreachable,
                .code = allocator.dupe(u8, file.code) catch unreachable,
            };
        }
        break :blk duped;
    } else blk: {
        const fallback = allocator.alloc(File, 1) catch unreachable;
        fallback[0] = .{ .filename = props.filename, .code = props.zx_code };
        break :blk fallback;
    };

    const file_radio_name = std.fmt.allocPrint(allocator, "file-{s}", .{props.id}) catch unreachable;

    // Process files to add computed fields
    const files: []const File = blk: {
        const result = allocator.alloc(File, input_files.len) catch unreachable;
        for (input_files, 0..) |file, i| {
            // Skip highlighting for empty or very large files (tree-sitter limit)
            const highlighted = if (file.code.len > 0 and file.code.len < 100_000)
                util.highlightZx(allocator, file.code) catch file.code
            else
                file.code;

            result[i] = .{
                .filename = file.filename,
                .code = file.code,
                .highlighted = highlighted,
                .radio_id = std.fmt.allocPrint(allocator, "file-{s}-{d}", .{ props.id, i }) catch unreachable,
                .content_id = std.fmt.allocPrint(allocator, "file-content-{s}-{d}", .{ props.id, i }) catch unreachable,
                .is_first = i == 0,
            };
        }
        break :blk result;
    };

    const html_with_style = std.fmt.allocPrint(allocator, "{s}{s}", .{ dark_mode_style, props.html_code }) catch unreachable;

    const preview_id = std.fmt.allocPrint(allocator, "tab-{s}-preview", .{props.id}) catch unreachable;
    const html_id = std.fmt.allocPrint(allocator, "tab-{s}-html", .{props.id}) catch unreachable;
    const zig_id = std.fmt.allocPrint(allocator, "tab-{s}-zig", .{props.id}) catch unreachable;
    const name_id = std.fmt.allocPrint(allocator, "tab-{s}", .{props.id}) catch unreachable;
    const preview_content_id = std.fmt.allocPrint(allocator, "tab-preview-{s}", .{props.id}) catch unreachable;
    const html_content_id = std.fmt.allocPrint(allocator, "tab-html-{s}", .{props.id}) catch unreachable;
    const zig_content_id = std.fmt.allocPrint(allocator, "tab-zig-{s}", .{props.id}) catch unreachable;

    return (
        <div class="sandbox" @allocator={allocator}>
            <div class="sandbox-container">
                <div class="sandbox-editor">
                    <div class="sandbox-editor-header">
                        <div class="sandbox-tabs sandbox-file-tabs">
                            {for (files) |file| (
                                <>
                                    <input @allocator={allocator} type="radio" id={file.radio_id} name={file_radio_name} class="file-radio" checked={file.is_first} />
                                    <label for={file.radio_id} class="sandbox-tab">
                                        <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">
                                            <path d="M13 9h5.5L13 3.5V9M6 2h8l6 6v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4c0-1.11.89-2 2-2m5 2H6v16h12v-9h-7V4z" />
                                        </svg>
                                        {file.filename}
                                    </label>
                                </>
                            )}
                        </div>
                    </div>
                    {for (files) |file| (
                        <div @allocator={allocator} class="sandbox-code file-content" id={file.content_id}>
                            <pre translate="no" class="sandbox-code-pre"><code class="hljs sandbox-code-lines" @escaping={.none}>{file.highlighted}</code></pre>
                        </div>
                    )}
                </div>

                <div class="sandbox-preview">
                    <div class="sandbox-preview-header">
                        <input type="radio" id={preview_id} name={name_id} class="tab-radio" checked="true" aria-label="Preview" />
                        <input type="radio" id={html_id} name={name_id} class="tab-radio" aria-label="HTML output" />
                        <input type="radio" id={zig_id} name={name_id} class="tab-radio" aria-label="Zig code" />
                        <div class="sandbox-preview-tabs">
                            <label for={preview_id} class="sandbox-preview-tab">Preview</label>
                            <label for={html_id} class="sandbox-preview-tab">HTML</label>
                        </div>
                        <div class="sandbox-preview-actions">
                            <button class="sandbox-action-btn" title="Reset">
                                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                                    <path d="M1 4v6h6M23 20v-6h-6" />
                                    <path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4-4.64 4.36A9 9 0 0 1 3.51 15" />
                                </svg>
                            </button>
                        </div>
                    </div>
                    <div class="sandbox-preview-content" id={preview_content_id}>
                        <iframe class="sandbox-preview-frame" srcdoc={html_with_style} title="Code example preview"></iframe>
                    </div>
                    <div class="sandbox-preview-content sandbox-code-content" id={html_content_id}>
                        <pre translate="no"><code class="language-markup">{props.html_code}</code></pre>
                    </div>
                    <div class="sandbox-preview-content sandbox-code-content" id={zig_content_id} style="display: none;">
                        <pre translate="no"><code class="language-zig">{props.zig_code}</code></pre>
                    </div>
                </div>
            </div>
        </div>
    );
}

// Wrap HTML with dark mode styles for iframe
const dark_mode_style =
    \\<style>
    \\  * { 
    \\    color-scheme: light dark; 
    \\    margin: 0;
    \\    padding: 0;
    \\    box-sizing: border-box;
    \\  }
    \\  html, body {
    \\    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    \\    line-height: 1.5;
    \\    padding: 1rem;
    \\  }
    \\  @media (prefers-color-scheme: dark) {
    \\    body { background: #16181d !important; color: #f6f7f9 !important; }
    \\    * { color: inherit; }
    \\  }
    \\  @media (prefers-color-scheme: light) {
    \\    body { background: #ffffff !important; color: #23272f !important; }
    \\  }
    \\</style>
;

const zx = @import("zx");
const std = @import("std");
const util = @import("../reference/util.zx");
