//go:build windows

package main

import (
	"fmt"
	"log"
	"os"
	"runtime"
	"sync"
	"syscall"
	"unsafe"
)

// Win32 常量
const (
	WS_OVERLAPPEDWINDOW = 0x00CF0000
	WS_CHILD            = 0x40000000
	WS_VISIBLE          = 0x10000000
	WS_VSCROLL          = 0x00200000
	WS_HSCROLL          = 0x00100000
	WS_EX_CLIENTEDGE    = 0x00000200

	ES_MULTILINE   = 0x0004
	ES_READONLY    = 0x0800
	ES_AUTOVSCROLL = 0x0040
	ES_AUTOHSCROLL = 0x0080

	WM_DESTROY      = 0x0002
	WM_SIZE         = 0x0005
	WM_SETFONT      = 0x0030
	WM_CTLCOLOREDIT = 0x0133
	EM_SETSEL       = 0x00B1
	EM_REPLACESEL   = 0x00C2

	SW_SHOW         = 5
	IDC_ARROW       = 32512
	CW_USEDEFAULT   = ^0x7FFFFFFF
	FIXED_PITCH     = 1
	FF_MODERN       = 48
	DEFAULT_CHARSET = 1
	FW_NORMAL       = 400
	MB_ICONERROR    = 0x00000010
)

// 暗色主题 (BGR格式)
const (
	colorBg = 0x001E1E1E
	colorFg = 0x00D4D4D4
)

type tWNDCLASSEX struct {
	CbSize        uint32
	Style         uint32
	LpfnWndProc   uintptr
	CbClsExtra    int32
	CbWndExtra    int32
	HInstance     uintptr
	HIcon         uintptr
	HCursor       uintptr
	HbrBackground uintptr
	LpszMenuName  *uint16
	LpszClassName *uint16
	HIconSm       uintptr
}

type tRECT struct {
	Left   int32
	Top    int32
	Right  int32
	Bottom int32
}

type tMSG struct {
	HWnd    uintptr
	Message uint32
	_       uint32
	WParam  uintptr
	LParam  uintptr
	Time    uint32
	PtX     int32
	PtY     int32
}

var (
	modUser32   = syscall.NewLazyDLL("user32.dll")
	modKernel32 = syscall.NewLazyDLL("kernel32.dll")
	modGdi32    = syscall.NewLazyDLL("gdi32.dll")

	pGetModuleHandleW = modKernel32.NewProc("GetModuleHandleW")
	pLoadCursorW      = modUser32.NewProc("LoadCursorW")
	pRegisterClassExW = modUser32.NewProc("RegisterClassExW")
	pCreateWindowExW  = modUser32.NewProc("CreateWindowExW")
	pShowWindow       = modUser32.NewProc("ShowWindow")
	pUpdateWindow     = modUser32.NewProc("UpdateWindow")
	pGetMessageW      = modUser32.NewProc("GetMessageW")
	pTranslateMessage = modUser32.NewProc("TranslateMessage")
	pDispatchMessageW = modUser32.NewProc("DispatchMessageW")
	pDefWindowProcW   = modUser32.NewProc("DefWindowProcW")
	pPostQuitMessage  = modUser32.NewProc("PostQuitMessage")
	pSendMessageW     = modUser32.NewProc("SendMessageW")
	pGetClientRect    = modUser32.NewProc("GetClientRect")
	pMoveWindow       = modUser32.NewProc("MoveWindow")
	pMessageBoxW      = modUser32.NewProc("MessageBoxW")
	pCreateFontW      = modGdi32.NewProc("CreateFontW")
	pDeleteObject     = modGdi32.NewProc("DeleteObject")
	pCreateSolidBrush = modGdi32.NewProc("CreateSolidBrush")
	pSetTextColor     = modGdi32.NewProc("SetTextColor")
	pSetBkColor       = modGdi32.NewProc("SetBkColor")
)

var (
	hWndMain    uintptr
	hWndEdit    uintptr
	hFont       uintptr
	hbrBg       uintptr
	guiReady    bool
	guiMu       sync.Mutex
	pendingLogs []string
)

// guiLogWriter 实现 io.Writer，将日志写入编辑控件
type guiLogWriter struct{}

func (w *guiLogWriter) Write(p []byte) (n int, err error) {
	text := string(p)

	guiMu.Lock()
	if !guiReady || hWndEdit == 0 {
		pendingLogs = append(pendingLogs, text)
		guiMu.Unlock()
		return len(p), nil
	}
	guiMu.Unlock()

	appendText(text)
	return len(p), nil
}

func appendText(text string) {
	if hWndEdit == 0 {
		return
	}
	// 光标移到末尾
	pSendMessageW.Call(hWndEdit, EM_SETSEL, ^uintptr(0), ^uintptr(0))
	// 插入文本
	ptr, _ := syscall.UTF16PtrFromString(text)
	pSendMessageW.Call(hWndEdit, EM_REPLACESEL, 1, uintptr(unsafe.Pointer(ptr)))
}

func flushPendingLogs() {
	guiMu.Lock()
	logs := pendingLogs
	pendingLogs = nil
	guiReady = true
	guiMu.Unlock()

	for _, text := range logs {
		appendText(text)
	}
}

func wndProc(hWnd uintptr, msg uint32, wParam, lParam uintptr) uintptr {
	switch msg {
	case WM_SIZE:
		if hWndEdit != 0 {
			var rect tRECT
			pGetClientRect.Call(hWnd, uintptr(unsafe.Pointer(&rect)))
			pMoveWindow.Call(hWndEdit, 0, 0, uintptr(rect.Right), uintptr(rect.Bottom), 1)
		}
		return 0

	case WM_CTLCOLOREDIT:
		pSetTextColor.Call(wParam, colorFg)
		pSetBkColor.Call(wParam, colorBg)
		return hbrBg

	case WM_DESTROY:
		if hFont != 0 {
			pDeleteObject.Call(hFont)
		}
		if hbrBg != 0 {
			pDeleteObject.Call(hbrBg)
		}
		pPostQuitMessage.Call(0)
		return 0
	}

	ret, _, _ := pDefWindowProcW.Call(hWnd, uintptr(msg), wParam, lParam)
	return ret
}

// runGUI 创建并运行GUI窗口，阻塞直到窗口关闭
func runGUI() {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	hInstance, _, _ := pGetModuleHandleW.Call(0)

	className, _ := syscall.UTF16PtrFromString("KfzLogWnd")
	windowTitle, _ := syscall.UTF16PtrFromString("孔网商品定价 - 日志")
	editClass, _ := syscall.UTF16PtrFromString("EDIT")

	hCursor, _, _ := pLoadCursorW.Call(0, IDC_ARROW)

	// 创建暗色背景画刷
	hbrBg, _, _ = pCreateSolidBrush.Call(colorBg)

	// 注册窗口类
	wc := tWNDCLASSEX{
		CbSize:        uint32(unsafe.Sizeof(tWNDCLASSEX{})),
		LpfnWndProc:   syscall.NewCallback(wndProc),
		HInstance:     hInstance,
		HCursor:       hCursor,
		HbrBackground: hbrBg,
		LpszClassName: className,
	}
	pRegisterClassExW.Call(uintptr(unsafe.Pointer(&wc)))

	// 创建主窗口
	hWndMain, _, _ = pCreateWindowExW.Call(
		0,
		uintptr(unsafe.Pointer(className)),
		uintptr(unsafe.Pointer(windowTitle)),
		WS_OVERLAPPEDWINDOW,
		100, 100, 900, 600,
		0, 0, hInstance, 0,
	)

	// 创建编辑控件（多行、只读、滚动条）
	hWndEdit, _, _ = pCreateWindowExW.Call(
		WS_EX_CLIENTEDGE,
		uintptr(unsafe.Pointer(editClass)),
		0,
		WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL|ES_MULTILINE|ES_READONLY|ES_AUTOVSCROLL|ES_AUTOHSCROLL,
		0, 0, 0, 0,
		hWndMain, 0, hInstance, 0,
	)

	// 设置等宽字体
	fontName, _ := syscall.UTF16PtrFromString("Consolas")
	hFont, _, _ = pCreateFontW.Call(
		16, 0, 0, 0, FW_NORMAL, 0, 0, 0,
		DEFAULT_CHARSET, 0, 0, 0,
		FIXED_PITCH|FF_MODERN,
		uintptr(unsafe.Pointer(fontName)),
	)
	pSendMessageW.Call(hWndEdit, WM_SETFONT, hFont, 1)

	// 刷新缓冲日志
	flushPendingLogs()

	// 显示窗口
	pShowWindow.Call(hWndMain, SW_SHOW)
	pUpdateWindow.Call(hWndMain)

	// 消息循环
	var msg tMSG
	for {
		ret, _, _ := pGetMessageW.Call(uintptr(unsafe.Pointer(&msg)), 0, 0, 0)
		if ret == 0 {
			break
		}
		pTranslateMessage.Call(uintptr(unsafe.Pointer(&msg)))
		pDispatchMessageW.Call(uintptr(unsafe.Pointer(&msg)))
	}
}

// fatalExit 弹出错误对话框并退出
func fatalExit(format string, v ...interface{}) {
	msg := fmt.Sprintf(format, v...)
	log.Print(msg)
	title, _ := syscall.UTF16PtrFromString("错误")
	text, _ := syscall.UTF16PtrFromString(msg)
	pMessageBoxW.Call(0, uintptr(unsafe.Pointer(text)), uintptr(unsafe.Pointer(title)), MB_ICONERROR)
	os.Exit(1)
}
