//go:build windows

/*
** Job Arranger for ZABBIX
** Copyright (C) 2025 Daiwa Institute of Research Ltd. All Rights Reserved.
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
**/

package logger

import (
	"os"

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

type windowsEventLog struct {
	log *eventlog.Log
}

func (w *windowsEventLog) WriteLog(logLevel LogLevel, message string) error {
	// Event IDs should be > 0 and ideally map to specific events
	// We'll use different IDs for different log levels
	eventID := uint32(1) // Default event ID
	switch logLevel {
	case LogLevelInfo:
		eventID = 1000
	case LogLevelWarn:
		eventID = 2000
	case LogLevelErr:
		eventID = 3000
	case LogLevelCrit:
		eventID = 4000
	}

	// Windows event log requires messages to be limited to 32766 characters
	if len(message) > 32766 {
		message = message[:32766]
	}

	switch logLevel {
	case LogLevelInfo:
		return w.log.Info(eventID, message)
	case LogLevelWarn:
		return w.log.Warning(eventID, message)
	case LogLevelErr, LogLevelCrit:
		return w.log.Error(eventID, message)
	default:
		return w.log.Info(eventID, message)
	}
}

func (w *windowsEventLog) Close() error {
	return w.log.Close()
}

func NewSystemLogger() (SystemLogger, error) {
	sourceName := "Job Arranger Agent2"

	// Install the event source if it doesn't exist (requires admin privileges)
	// This is typically done during installation, not at runtime
	// eventlog.InstallAsEventCreate(sourceName, eventlog.Error|eventlog.Warning|eventlog.Info)

	// Open the event log
	el, err := eventlog.Open(sourceName)
	if err != nil {
		return nil, err
	}
	return &windowsEventLog{log: el}, nil
}

// Mutex locker
type windowsMutexLocker struct {
}

func (mu *windowsMutexLocker) LockFile(f *os.File) error {
	handle := windows.Handle(f.Fd())

	var overlapped windows.Overlapped
	return windows.LockFileEx(
		handle,
		windows.LOCKFILE_EXCLUSIVE_LOCK,
		0,
		0xFFFFFFFF, 0xFFFFFFFF, // Lock the entire file
		&overlapped,
	)
}

func (mu *windowsMutexLocker) UnlockFile(f *os.File) error {
	handle := windows.Handle(f.Fd())

	var overlapped windows.Overlapped
	return windows.UnlockFileEx(handle,
		0,
		0xFFFFFFFF, 0xFFFFFFFF,
		&overlapped,
	)
}

func NewMutexLocker() (MutexLocker, error) {
	return &windowsMutexLocker{}, nil
}
