const geometry = @import("geometry");
const platform = @import("../platform/root.zig");

pub const RuntimeSourceStorage = struct {
    bytes: [platform.max_window_source_bytes]u8 = undefined,
    asset_root_path: [platform.max_window_source_path_bytes]u8 = undefined,
    asset_entry: [platform.max_window_source_path_bytes]u8 = undefined,
    asset_origin: [platform.max_window_source_path_bytes]u8 = undefined,
};

pub fn copySourceInto(storage: *RuntimeSourceStorage, source: platform.WebViewSource) !platform.WebViewSource {
    var copied = source;
    copied.bytes = try copyWindowSourceField(&storage.bytes, source.bytes);
    if (source.asset_options) |assets| {
        copied.asset_options = .{
            .root_path = try copyWindowSourceField(&storage.asset_root_path, assets.root_path),
            .entry = try copyWindowSourceField(&storage.asset_entry, assets.entry),
            .origin = try copyWindowSourceField(&storage.asset_origin, assets.origin),
            .spa_fallback = assets.spa_fallback,
        };
    }
    return copied;
}

pub const RuntimeWindow = struct {
    info: platform.WindowInfo = .{},
    main_view_id: platform.ViewId = 0,
    source: ?platform.WebViewSource = null,
    source_reloads_from_app: bool = false,
    /// Retained so hot reload never materializes an app WebView in a
    /// deliberately sourceless canvas window.
    source_policy: WindowSourcePolicy = .allow_source_less,
    /// Creation-time show policy retained so Runtime.showWindow mirrors
    /// whether the native host passively orders front or activates.
    activate_on_show: bool = true,
    main_frame: geometry.RectF = geometry.RectF.init(0, 0, 0, 0),
    main_frame_set: bool = false,
    main_layer: i32 = 0,
    main_parent: ?[]const u8 = null,
    main_zoom: f64 = 1.0,
    main_focused: bool = false,
    label_storage: [platform.max_window_label_bytes]u8 = undefined,
    title_storage: [platform.max_window_title_bytes]u8 = undefined,
    main_parent_storage: [platform.max_view_label_bytes]u8 = undefined,
    source_storage: RuntimeSourceStorage = .{},
};

pub const RuntimeMainWebViewState = struct {
    frame: geometry.RectF = geometry.RectF.init(0, 0, 0, 0),
    frame_set: bool = false,
    layer: i32 = 0,
    parent: ?[]const u8 = null,
    parent_storage: [platform.max_view_label_bytes]u8 = undefined,
};

pub const RuntimeWebView = struct {
    id: platform.ViewId = 0,
    window_id: platform.WindowId = 1,
    label: []const u8 = "",
    parent: ?[]const u8 = null,
    url: []const u8 = "",
    frame: geometry.RectF = geometry.RectF.init(0, 0, 0, 0),
    local_frame: geometry.RectF = geometry.RectF.init(0, 0, 0, 0),
    layer: i32 = 0,
    zoom: f64 = 1.0,
    transparent: bool = false,
    bridge_enabled: bool = false,
    focused: bool = false,
    open: bool = false,
    label_storage: [platform.max_webview_label_bytes]u8 = undefined,
    parent_storage: [platform.max_view_label_bytes]u8 = undefined,
    url_storage: [platform.max_webview_url_bytes]u8 = undefined,
};

pub const RuntimeTrayItem = struct {
    id: platform.TrayItemId = 0,
    command: []const u8 = "",
    label: []const u8 = "",
    separator: bool = false,
    enabled: bool = true,
    detail: []const u8 = "",
    role: platform.TrayItemRole = .command,
    key: []const u8 = "",
    modifiers: platform.ShortcutModifiers = .{},
    command_storage: [platform.max_tray_item_command_bytes]u8 = undefined,
    label_storage: [platform.max_tray_item_label_bytes]u8 = undefined,
    detail_storage: [platform.max_tray_item_detail_bytes]u8 = undefined,
    key_storage: [platform.max_menu_key_bytes]u8 = undefined,
    segment_options: [platform.max_tray_segment_options]platform.TraySegmentOption = undefined,
    segment_option_label_storage: [platform.max_tray_segment_options][platform.max_tray_segment_label_bytes]u8 = undefined,
    segment_option_command_storage: [platform.max_tray_segment_options][platform.max_tray_item_command_bytes]u8 = undefined,
    segment_option_count: usize = 0,
    segmented: ?platform.TraySegmentedRow = null,
    metric_primary_storage: [platform.max_tray_item_label_bytes]u8 = undefined,
    metric_secondary_storage: [platform.max_tray_item_detail_bytes]u8 = undefined,
    metric_accessibility_storage: [platform.max_tray_chart_text_bytes]u8 = undefined,
    metric: ?platform.TrayMetricRow = null,
    chart_values: [platform.max_tray_chart_values]f32 = undefined,
    chart_leading_caption_storage: [platform.max_tray_chart_text_bytes]u8 = undefined,
    chart_trailing_summary_storage: [platform.max_tray_chart_text_bytes]u8 = undefined,
    chart_accessibility_label_storage: [platform.max_tray_chart_text_bytes]u8 = undefined,
    chart: ?platform.TrayChartRow = null,
};

pub const RuntimeStatusItem = struct {
    id: platform.StatusItemId = 0,
    active: bool = false,
    visible: bool = true,
    title: []const u8 = "",
    title_storage: [platform.max_tray_title_bytes]u8 = undefined,
    items: [platform.max_tray_items]RuntimeTrayItem = undefined,
    item_count: usize = 0,
};

pub const ShellApplyMode = enum {
    create,
    update,
};

pub const WindowSourcePolicy = enum {
    require_source,
    allow_source_less,
    /// Never host the app webview source, even when one is loaded: the
    /// shape for model-driven canvas windows whose whole content is
    /// their gpu_surface view.
    never_source,
};

pub const FocusTraversalDirection = enum {
    next,
    previous,
};

pub fn sourceWebViewUrl(source: ?platform.WebViewSource) []const u8 {
    const value = source orelse return "";
    return switch (value.kind) {
        .html => "zero://inline",
        .url, .assets => value.bytes,
    };
}

fn copyWindowSourceField(buffer: []u8, value: []const u8) ![]const u8 {
    if (value.len > buffer.len) return error.WindowSourceTooLarge;
    @memcpy(buffer[0..value.len], value);
    return buffer[0..value.len];
}
