/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * or in the "license" file accompanying this file. This file 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 logger // import "aws-observability.io/collector/logger

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"

	"github.com/aws-observability/aws-otel-collector/pkg/extraconfig"
)

var (
	UnixLogPath      = "/opt/aws/aws-otel-collector/logs/aws-otel-collector.log"
	WindowsLogPath   = "C:\\ProgramData\\Amazon\\AWSOTelCollector\\Logs\\aws-otel-collector.log"
	logfile          = getLogFilePath()
	lumberjackLogger = tryNewLumberJackLogger()
)

func tryNewLumberJackLogger() *lumberjack.Logger {
	if logfile != "" && !extraconfig.IsRunningInContainer() {
		return &lumberjack.Logger{
			Filename:   logfile,
			MaxSize:    100, //MB
			MaxBackups: 5,   //backup files
			MaxAge:     7,   //days
			Compress:   true,
		}
	}
	return nil
}

// WrapCoreOpt returns a zap.Option that wraps the provided core, teeing the output to the lumberjack writer.
// It uses a JSON encoder and the same level as the provided core.
// If the lumberjack logger is not configured returns the provided core unmodified.
func WrapCoreOpt() zap.Option {
	return zap.WrapCore(func(core zapcore.Core) zapcore.Core {
		if lumberjackLogger == nil {
			return core
		}

		encoderConfig := zapcore.EncoderConfig{
			MessageKey:     "message",
			LevelKey:       "level",
			TimeKey:        "timestamp",
			CallerKey:      "caller",
			StacktraceKey:  "stack",
			EncodeLevel:    zapcore.LowercaseLevelEncoder,
			EncodeTime:     zapcore.ISO8601TimeEncoder,
			EncodeDuration: zapcore.MillisDurationEncoder,
			EncodeCaller:   zapcore.ShortCallerEncoder,
		}
		return zapcore.NewTee(core, zapcore.NewCore(zapcore.NewJSONEncoder(encoderConfig), zapcore.AddSync(lumberjackLogger), core.(zapcore.LevelEnabler)))
	})
}

// SetupErrorLogger setup lumberjackLogger for go logger
func SetupErrorLogger() {
	var writer io.WriteCloser
	// When running in container, always log to stderr, it makes debugging easier.
	if lumberjackLogger != nil {
		err := os.MkdirAll(filepath.Dir(logfile), 0755)
		if err != nil {
			log.Printf("D! fail to chmod on log file due to : %v \n", err)
		}
		// The codes below should not change, because the retention information has already been published to public doc.
		writer = lumberjackLogger
	} else {
		writer = os.Stderr
	}
	log.SetOutput(writer)
}

// getLogFilePath retuns the log file path depending on the OS.
func getLogFilePath() string {
	if runtime.GOOS == "windows" {
		return WindowsLogPath
	}
	return UnixLogPath
}

// SetLogLevel allows to set log level by parameter
// possible values (DEBUG, INFO, WARN, ERROR, DPANIC, PANIC, FATAL)
func SetLogLevel(level string) {
	if level != "" {
		os.Args = append(os.Args, fmt.Sprintf("--config=yaml:service::telemetry::logs::level: %s", level))
	}
}
