//go:build windows
// +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 agentutils

import (
	"fmt"
	"io"
	"jobarranger2/src/libs/golibs/logger/logger"
	"os"
	"strconv"
	"strings"
	"syscall"

	"golang.org/x/text/encoding"
	"golang.org/x/text/encoding/charmap"
	"golang.org/x/text/encoding/japanese"
	"golang.org/x/text/encoding/korean"
	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/encoding/traditionalchinese"
	"golang.org/x/text/encoding/unicode"
	"golang.org/x/text/transform"
)

// コードページ→エンコーディング対応表
var codePageEncodings = map[uint32]encoding.Encoding{
	// Unicode
	65001: unicode.UTF8,
	1200:  unicode.UTF16(unicode.LittleEndian, unicode.ExpectBOM),
	1201:  unicode.UTF16(unicode.BigEndian, unicode.ExpectBOM),

	// UTF-16 BOM無し（仮想コードページ）
	0xFFFF1200: unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM),
	0xFFFF1201: unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM),

	// 日本語
	932: japanese.ShiftJIS,

	// 中国語
	936: simplifiedchinese.GBK,
	950: traditionalchinese.Big5,

	// 韓国語
	949: korean.EUCKR,

	// Windows-125x
	1250: charmap.Windows1250,
	1251: charmap.Windows1251,
	1252: charmap.Windows1252,
	1253: charmap.Windows1253,
	1254: charmap.Windows1254,
	1255: charmap.Windows1255,
	1256: charmap.Windows1256,
	1257: charmap.Windows1257,
	1258: charmap.Windows1258,

	// ISO-8859-x
	28591: charmap.ISO8859_1,
	28592: charmap.ISO8859_2,
	28593: charmap.ISO8859_3,
	28594: charmap.ISO8859_4,
	28595: charmap.ISO8859_5,
	28596: charmap.ISO8859_6,
	28597: charmap.ISO8859_7,
	28598: charmap.ISO8859_8,
	28599: charmap.ISO8859_9,
	28603: charmap.ISO8859_13,
	28605: charmap.ISO8859_15,

	// DOS系
	437: charmap.CodePage437,
	850: charmap.CodePage850,
	852: charmap.CodePage852,
	855: charmap.CodePage855,
	//857: charmap.CodePage857,
	858: charmap.CodePage858,
	860: charmap.CodePage860,
	//861: charmap.CodePage861,
	862: charmap.CodePage862,
	863: charmap.CodePage863,
	865: charmap.CodePage865,
}

var (
	kernel32                = syscall.NewLazyDLL("kernel32.dll")
	procgetACP              = kernel32.NewProc("GetACP")
	procWideCharToMultiByte = kernel32.NewProc("WideCharToMultiByte")
	procMultiByteToWideChar = kernel32.NewProc("MultiByteToWideChar")
)

// システムの現在のアクティブコードページを取得
func getACP() uint32 {
	ret, _, _ := procgetACP.Call()
	return uint32(ret)
}

// コードページに応じたエンコーディングを選択
func selectEncoding(acp uint32) encoding.Encoding {
	fn := "selectEncoding"
	enc, ok := codePageEncodings[acp]
	if !ok {
		// Set code page as OS default
		defaultCodePage := getACP()
		enc, _ := codePageEncodings[defaultCodePage]
		logger.WriteLog("JAAGENTMNG300005", fn, acp, defaultCodePage)
		return enc
	}
	return enc
}

func ReadFileAsLocale(filePath string, locale string) (string, error) {
	fn := "ReadFileAsLocale"
	var codePage uint32
	if locale != "" {
		if codePageInt, err := strconv.Atoi(locale); err == nil {
			// Set code page as config parameter
			codePage = uint32(codePageInt)
		} else {
			// Set code page as OS default
			codePage = getACP()
			logger.WriteLog("JAAGENTMNG200035", fn, locale, codePage, filePath)
		}
	} else {
		// Set code page as OS default
		codePage = getACP()
	}

	enc := selectEncoding(codePage)

	f, err := os.Open(filePath)
	if err != nil {
		return "", fmt.Errorf("failed to open file: %w", err)
	}
	defer f.Close()

	reader := transform.NewReader(f, enc.NewDecoder())

	// Read the file, decoding from the specified locale/code page to UTF-8
	utf8Bytes, err := io.ReadAll(reader)
	if err != nil {
		return "", fmt.Errorf("failed to decode file content: %w", err)
	}

	return string(utf8Bytes), nil
}

func WriteFileAsLocale(filePath, utf8String, locale string) error {
	fn := "WriteFileAsLocale"
	f, err := os.Create(filePath)
	if err != nil {
		return fmt.Errorf("error creating file: %v", err)
	}

	var codePage uint32
	if locale != "" {
		if codePageInt, err := strconv.Atoi(locale); err == nil {
			// Set code page as config parameter
			codePage = uint32(codePageInt)
		} else {
			// Set code page as OS default
			codePage = getACP()
			logger.WriteLog("JAAGENTMNG200035", fn, locale, codePage, filePath)
		}
	} else {
		// Set code page as OS default
		codePage = getACP()
	}

	enc := selectEncoding(codePage)
	writer := transform.NewWriter(f, enc.NewEncoder())

	utf8String = strings.ReplaceAll(utf8String, "\n", "\r\n")
	_, err = writer.Write([]byte(utf8String))
	if err != nil {
		return fmt.Errorf("failed to write encoded data: %w", err)
	}

	writer.Close()
	f.Close()

	logger.WriteLog("JAAGENTMNG000012", fn, enc, filePath)
	return nil
}

func EncodeEnv(envMap map[string]string, locale string) ([]string, error) {
	fn := "EncodeEnv"
	var codePage uint32
	if locale != "" {
		if codePageInt, err := strconv.Atoi(locale); err == nil {
			// Set code page as config parameter
			codePage = uint32(codePageInt)
		} else {
			// Set code page as OS default
			codePage = getACP()
			logger.WriteLog("JAAGENTMNG200036", fn, locale, codePage)
		}
	} else {
		// Set code page as OS default
		codePage = getACP()
	}

	enc := selectEncoding(codePage)

	var encodedEnv []string

	for k, v := range envMap {
		encodedValue, _, err := transform.String(enc.NewEncoder(), v)
		if err != nil {
			return nil, fmt.Errorf("env encoding error for key %s: %w", k, err)
		}
		encodedEnv = append(encodedEnv, fmt.Sprintf("%s=%s", k, encodedValue))
	}
	return encodedEnv, nil
}

func EncodeString(orgStr string, locale string) (string, error) {
	return orgStr, nil
}

func DecodeString(orgStr string, locale string) (string, error) {
	return orgStr, nil
}
