package main

import (
	"fmt"
	"unicode/utf16"
	"unsafe"

	"golang.org/x/sys/windows"
)

var (
	comdlg32             = windows.NewLazySystemDLL("comdlg32.dll")
	procGetOpenFileNameW = comdlg32.NewProc("GetOpenFileNameW")
	procChooseColorW     = comdlg32.NewProc("ChooseColorW")

	shell32                  = windows.NewLazySystemDLL("shell32.dll")
	procSHBrowseForFolderW   = shell32.NewProc("SHBrowseForFolderW")
	procSHGetPathFromIDListW = shell32.NewProc("SHGetPathFromIDListW")

	ole32dll          = windows.NewLazySystemDLL("ole32.dll")
	procCoTaskMemFree = ole32dll.NewProc("CoTaskMemFree")
)

func slicePtr(s interface{}) uintptr {
	switch v := s.(type) {
	case []uint16:
		if len(v) == 0 {
			return 0
		}
		return uintptr(unsafe.Pointer(&v[0]))
	case []uint32:
		if len(v) == 0 {
			return 0
		}
		return uintptr(unsafe.Pointer(&v[0]))
	}
	return 0
}

func openFileDialog(owner uintptr) string {
	type openFileName struct {
		lStructSize       uint32
		hwndOwner         uintptr
		hInstance         uintptr
		lpstrFilter       uintptr
		lpstrCustomFilter uintptr
		nMaxCustFilter    uint32
		nFilterIndex      uint32
		lpstrFile         uintptr
		nMaxFile          uint32
		lpstrFileTitle    uintptr
		nMaxFileTitle     uint32
		lpstrInitialDir   uintptr
		lpstrTitle        uintptr
		Flags             uint32
		nFileOffset       uint16
		nFileExtension    uint16
		lpstrDefExt       uintptr
		lCustData         uintptr
		lpfnHook          uintptr
		lpTemplateName    uintptr
		pvReserved        uintptr
		dwReserved        uint32
		FlagsEx           uint32
	}

	// Filter: "Images\0*.jpg;*.png\0All\0*.*\0\0"
	filterStr := "图片文件\x00*.jpg;*.jpeg;*.png;*.bmp;*.webp;*.gif\x00所有文件\x00*.*\x00\x00"
	filterUTF16 := utf16.Encode([]rune(filterStr))

	titleUTF16 := utf16.Encode([]rune("选择壁纸图片"))
	fileBuf := make([]uint16, 260)

	ofn := openFileName{
		lStructSize: uint32(unsafe.Sizeof(openFileName{})),
		hwndOwner:   owner,
		lpstrFilter: slicePtr(filterUTF16),
		lpstrFile:   slicePtr(fileBuf),
		nMaxFile:    260,
		lpstrTitle:  slicePtr(titleUTF16),
		Flags:       0x00001000 | 0x00000800 | 0x00000004,
	}

	ret, _, _ := procGetOpenFileNameW.Call(uintptr(unsafe.Pointer(&ofn)))
	if ret == 0 {
		return ""
	}
	return windows.UTF16ToString(fileBuf)
}

func colorPickerDialog(owner uintptr, initialColor string) string {
	type chooseColor struct {
		lStructSize    uint32
		hwndOwner      uintptr
		hInstance      uintptr
		rgbResult      uint32
		lpCustColors   uintptr
		Flags          uint32
		lCustData      uintptr
		lpfnHook       uintptr
		lpTemplateName uintptr
	}

	custColors := make([]uint32, 16)

	var initRGB uint32
	if len(initialColor) > 4 && initialColor[0] == '#' {
		var r, g, b uint32
		fmt.Sscanf(initialColor[1:], "%02x%02x%02x", &r, &g, &b)
		initRGB = r | (g << 8) | (b << 16)
	}

	cc := chooseColor{
		lStructSize:  uint32(unsafe.Sizeof(chooseColor{})),
		hwndOwner:    owner,
		rgbResult:    initRGB,
		lpCustColors: slicePtr(custColors),
		Flags:        0x00000002,
	}

	ret, _, _ := procChooseColorW.Call(uintptr(unsafe.Pointer(&cc)))
	if ret == 0 {
		return ""
	}

	r := cc.rgbResult & 0xFF
	g := (cc.rgbResult >> 8) & 0xFF
	b := (cc.rgbResult >> 16) & 0xFF
	return fmt.Sprintf("#%02x%02x%02x", r, g, b)
}

func browseForFolderDialog(owner uintptr) string {
	title, _ := windows.UTF16PtrFromString("选择图片目录")
	var displayName [260]uint16

	bi := struct {
		HwndOwner      uintptr
		PidlRoot       uintptr
		PszDisplayName uintptr
		LpszTitle      uintptr
		UlFlags        uint32
		LpFn           uintptr
		LParam         uintptr
		IImage         int32
	}{
		HwndOwner:      owner,
		PszDisplayName: uintptr(unsafe.Pointer(&displayName[0])),
		LpszTitle:      uintptr(unsafe.Pointer(title)),
		UlFlags:        0x00000001 | 0x00000040,
	}

	pidl, _, _ := procSHBrowseForFolderW.Call(uintptr(unsafe.Pointer(&bi)))
	if pidl == 0 {
		return ""
	}
	defer procCoTaskMemFree.Call(pidl)

	var path [260]uint16
	procSHGetPathFromIDListW.Call(pidl, uintptr(unsafe.Pointer(&path[0])))
	return windows.UTF16ToString(path[:])
}
