//go:build linux
// +build linux

/*
** 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"
	"strings"

	"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"
)

// Map locale name or keyword to encoding.
var localeEncodingMap = map[string]encoding.Encoding{
	"UTF-8":        unicode.UTF8,
	"UTF8":         unicode.UTF8,
	"SHIFT_JIS":    japanese.ShiftJIS,
	"SHIFT-JIS":    japanese.ShiftJIS,
	"SJIS":         japanese.ShiftJIS,
	"EUC-JP":       japanese.EUCJP,
	"ISO-2022-JP":  japanese.ISO2022JP,
	"GBK":          simplifiedchinese.GBK,
	"GB2312":       simplifiedchinese.HZGB2312,
	"BIG5":         traditionalchinese.Big5,
	"ISO-8859-1":   charmap.ISO8859_1,
	"ISO-8859-2":   charmap.ISO8859_2,
	"ISO-8859-3":   charmap.ISO8859_3,
	"ISO-8859-4":   charmap.ISO8859_4,
	"ISO-8859-5":   charmap.ISO8859_5,
	"ISO-8859-6":   charmap.ISO8859_6,
	"ISO-8859-7":   charmap.ISO8859_7,
	"ISO-8859-8":   charmap.ISO8859_8,
	"ISO-8859-9":   charmap.ISO8859_9,
	"ISO-8859-13":  charmap.ISO8859_13,
	"ISO-8859-15":  charmap.ISO8859_15,
	"WINDOWS-1250": charmap.Windows1250,
	"WINDOWS-1251": charmap.Windows1251,
	"WINDOWS-1252": charmap.Windows1252,
	"WINDOWS-1253": charmap.Windows1253,
	"WINDOWS-1254": charmap.Windows1254,
	"WINDOWS-1255": charmap.Windows1255,
	"WINDOWS-1256": charmap.Windows1256,
	"WINDOWS-1257": charmap.Windows1257,
	"WINDOWS-1258": charmap.Windows1258,
	"KOI8-R":       charmap.KOI8R,
	"KOI8-U":       charmap.KOI8U,
	"CP437":        charmap.CodePage437,
	"CP850":        charmap.CodePage850,
	"CP852":        charmap.CodePage852,
	"CP855":        charmap.CodePage855,
	// "CP857":        charmap.CodePage857,
	"CP860": charmap.CodePage860,
	// "CP861":        charmap.CodePage861,
	"CP863": charmap.CodePage863,
	"CP865": charmap.CodePage865,
	"EUCKR": korean.EUCKR,
}

func detectEncoding(locale string) encoding.Encoding {
	// Check the LANG, LC_CTYPE, and LC_ALL environment variables.
	if locale == "" {
		locale = os.Getenv("LC_ALL")
	}
	if locale == "" {
		locale = os.Getenv("LC_CTYPE")
	}
	if locale == "" {
		locale = os.Getenv("LANG")
	}
	if locale == "" {
		// Default: UTF-8
		return unicode.UTF8
	}

	upperLocale := strings.ToUpper(locale)

	// Extract keywords from the locale.
	for keyword, enc := range localeEncodingMap {
		if strings.Contains(upperLocale, keyword) {
			return enc
		}
	}

	// Default: UTF-8
	return unicode.UTF8
}

// Read the file with the provided encoding
func ReadFileAsLocale(filePath string, locale string) (string, error) {
	enc := detectEncoding(locale)

	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 all data
	localeBytes, err := io.ReadAll(reader)
	if err != nil {
		return "", fmt.Errorf("failed to decode file content: %w", err)
	}

	return string(localeBytes), nil
}

// WriteFileAsLocale Write the utf8String into a file with the system's locale
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)
	}

	enc := detectEncoding(locale)
	writer := transform.NewWriter(f, enc.NewEncoder())

	utf8String = strings.ReplaceAll(utf8String, "\r\n", "\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) {
	enc := detectEncoding(locale)

	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) {
	enc := detectEncoding(locale)
	var encodedStr string

	encodedStr, _, err := transform.String(enc.NewEncoder(), orgStr)
	if err != nil {
		return "", fmt.Errorf("encoding error string '%s': %w", orgStr, err)
	}

	return encodedStr, nil
}

func DecodeString(encodedStr string, locale string) (string, error) {
	enc := detectEncoding(locale)

	decodedStr, _, err := transform.String(enc.NewDecoder(), encodedStr)
	if err != nil {
		return "", fmt.Errorf("decoding error string '%s': %w", encodedStr, err)
	}

	return decodedStr, nil
}
