package osdialog

import "core:c"
import "core:strings"

// ─── Enums ────────────────────────────────────────────────────────

Message_Level :: enum c.int {
	INFO    = 0,
	WARNING = 1,
	ERROR   = 2,
}

Message_Buttons :: enum c.int {
	OK        = 0,
	OK_CANCEL = 1,
	YES_NO    = 2,
}

File_Action :: enum c.int {
	OPEN     = 0,
	OPEN_DIR = 1,
	SAVE     = 2,
}

Color :: struct {
	r, g, b, a: u8,
}

// ─── Filter Types ─────────────────────────────────────────────────

Filter_Patterns :: struct {
	pattern: cstring,
	next:    ^Filter_Patterns,
}

Filters :: struct {
	name:     cstring,
	patterns: ^Filter_Patterns,
	next:     ^Filters,
}

// ─── Foreign Imports ──────────────────────────────────────────────

foreign import osdialog_lib "system:osdialog"
foreign import libc "system:c"

@(default_calling_convention = "c")
foreign osdialog_lib {
	osdialog_message       :: proc(level: Message_Level, buttons: Message_Buttons, message: cstring) -> c.int ---
	osdialog_prompt        :: proc(level: Message_Level, message: cstring, text: cstring) -> cstring ---
	osdialog_file          :: proc(action: File_Action, dir: cstring, filename: cstring, filters: ^Filters) -> cstring ---
	osdialog_filters_parse :: proc(str: cstring) -> ^Filters ---
	osdialog_filters_free  :: proc(filters: ^Filters) ---
	osdialog_color_picker  :: proc(color: ^Color, opacity: c.int) -> c.int ---
	osdialog_strdup        :: proc(s: cstring) -> cstring ---
	osdialog_strndup       :: proc(s: cstring, n: c.size_t) -> cstring ---
}

@(default_calling_convention = "c")
foreign libc {
	free :: proc(ptr: rawptr) ---
}

// ─── Convenience Wrappers ─────────────────────────────────────────

@(private)
alloc_cstr :: proc(s: string) -> cstring {
	if len(s) == 0 { return nil }
	return strings.clone_to_cstring(s)
}

@(private)
free_cstr :: proc(cs: cstring) {
	if cs != nil { delete(cs) }
}

open_file_dialog :: proc(default_dir: string = "", filters_str: string = "") -> string {
	dir_c := alloc_cstr(default_dir)
	defer free_cstr(dir_c)
	filter_c := alloc_cstr(filters_str)
	defer free_cstr(filter_c)
	filters: ^Filters
	if filter_c != nil {
		filters = osdialog_filters_parse(filter_c)
		defer osdialog_filters_free(filters)
	}
	result := osdialog_file(.OPEN, dir_c, nil, filters)
	if result == nil { return "" }
	defer free(rawptr(result))
	return string(result)
}

save_file_dialog :: proc(default_dir: string = "", default_name: string = "", filters_str: string = "") -> string {
	dir_c := alloc_cstr(default_dir)
	defer free_cstr(dir_c)
	name_c := alloc_cstr(default_name)
	defer free_cstr(name_c)
	filter_c := alloc_cstr(filters_str)
	defer free_cstr(filter_c)
	filters: ^Filters
	if filter_c != nil {
		filters = osdialog_filters_parse(filter_c)
		defer osdialog_filters_free(filters)
	}
	result := osdialog_file(.SAVE, dir_c, name_c, filters)
	if result == nil { return "" }
	defer free(rawptr(result))
	return string(result)
}

open_folder_dialog :: proc(default_dir: string = "") -> string {
	dir_c := alloc_cstr(default_dir)
	defer free_cstr(dir_c)
	result := osdialog_file(.OPEN_DIR, dir_c, nil, nil)
	if result == nil { return "" }
	defer free(rawptr(result))
	return string(result)
}

show_message :: proc(level: Message_Level, buttons: Message_Buttons, message: string) -> bool {
	msg_c := alloc_cstr(message)
	defer free_cstr(msg_c)
	result := osdialog_message(level, buttons, msg_c)
	return result == 1
}

show_prompt :: proc(level: Message_Level, message: string, default_text: string = "") -> string {
	msg_c := alloc_cstr(message)
	defer free_cstr(msg_c)
	text_c := alloc_cstr(default_text)
	defer free_cstr(text_c)
	result := osdialog_prompt(level, msg_c, text_c)
	if result == nil { return "" }
	defer free(rawptr(result))
	return string(result)
}

pick_color :: proc(r, g, b: u8, a: u8 = 255) -> (Color, bool) {
	color := Color{r, g, b, a}
	ok := osdialog_color_picker(&color, 1)
	return color, ok == 1
}
