/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package golang

import (
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/apache/rocketmq-clients/golang/v5/pkg/utils"
	"github.com/natefinch/lumberjack"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

const (
	CLIENT_LOG_ROOT     = "rocketmq.client.logRoot"
	CLIENT_LOG_MAXINDEX = "rocketmq.client.logFileMaxIndex"
	CLIENT_LOG_FILESIZE = "rocketmq.client.logFileMaxSize"
	CLIENT_LOG_LEVEL    = "rocketmq.client.logLevel"
	// CLIENT_LOG_ADDITIVE        = "rocketmq.client.log.additive"
	CLIENT_LOG_FILENAME = "rocketmq.client.logFileName"
	// CLIENT_LOG_ASYNC_QUEUESIZE = "rocketmq.client.logAsyncQueueSize"
	ENABLE_CONSOLE_APPENDER = "mq.consoleAppender.enabled"

	// Default log configuration values
	defaultLogMaxIndex    = 10
	defaultLogMaxFileSize = 100 // unit: MB
)

var sugarBaseLogger *zap.SugaredLogger

func ResetLogger() {
	InitLogger()
}

func InitLogger() {
	writeSyncer := getLogWriter()
	isStdOut := utils.GetenvWithDef(ENABLE_CONSOLE_APPENDER, "false")
	if isStdOut == "true" {
		writeSyncer = os.Stdout
	}
	encoder := getEncoder()

	var atomicLevel = zap.NewAtomicLevel()
	switch strings.ToLower(os.Getenv(CLIENT_LOG_LEVEL)) {
	case "debug":
		atomicLevel.SetLevel(zap.DebugLevel)
	case "warn":
		atomicLevel.SetLevel(zap.WarnLevel)
	case "error":
		atomicLevel.SetLevel(zap.ErrorLevel)
	default:
		atomicLevel.SetLevel(zap.InfoLevel)
	}

	core := zapcore.NewCore(encoder, writeSyncer, atomicLevel)

	logger := zap.New(core, zap.AddCaller())
	sugarBaseLogger = logger.Sugar()
}

func getEncoder() zapcore.Encoder {
	encoderConfig := zap.NewProductionEncoderConfig()
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	return zapcore.NewConsoleEncoder(encoderConfig)
}

func getLogWriter() zapcore.WriteSyncer {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		homeDir = "/tmp" // fallback to /tmp if home dir cannot be determined
	}
	clientLogRoot := utils.GetenvWithDef(CLIENT_LOG_ROOT, homeDir+"/logs/rocketmq")
	clientLogMaxIndexStr := utils.GetenvWithDef(CLIENT_LOG_MAXINDEX, strconv.Itoa(defaultLogMaxIndex))
	clientLogFileName := utils.GetenvWithDef(CLIENT_LOG_FILENAME, "rocketmq_client_go.log")
	clientLogMaxFileSizeStr := utils.GetenvWithDef(CLIENT_LOG_FILESIZE, strconv.Itoa(defaultLogMaxFileSize)) // unit: MB

	logFileName := clientLogRoot + "/" + clientLogFileName
	maxFileIndex, err := strconv.Atoi(clientLogMaxIndexStr)
	if err != nil {
		log.Printf("%s='%s' is invalid and has been replaced with the default value %d", CLIENT_LOG_MAXINDEX, clientLogMaxIndexStr, defaultLogMaxIndex)
		maxFileIndex = defaultLogMaxIndex
	}
	maxFileSize, err := strconv.Atoi(clientLogMaxFileSizeStr)
	if err != nil {
		log.Printf("%s='%s' is invalid and has been replaced with the default value %d", CLIENT_LOG_FILESIZE, clientLogMaxFileSizeStr, defaultLogMaxFileSize)
		maxFileSize = defaultLogMaxFileSize
	}
	lumberJackLogger := &lumberjack.Logger{
		Filename:   logFileName,
		MaxSize:    maxFileSize,
		MaxBackups: maxFileIndex,
		LocalTime:  true, // use local time, default is UTC
		Compress:   false,
	}
	return zapcore.AddSync(lumberJackLogger)
}

func init() {
	InitLogger()
}
