package simulation

import (
	"fmt"
	"os"
	"path"
	"sync"
	"time"
)

// log writter
type LogWriter interface {
	AddEntry(OperationEntry)
	PrintLogs()
}

// LogWriter - return a dummy or standard log writer given the testingmode
func NewLogWriter(testingmode bool) LogWriter {
	if !testingmode {
		return &DummyLogWriter{}
	}

	return &StandardLogWriter{}
}

// log writter
type StandardLogWriter struct {
	Seed int64

	OpEntries []OperationEntry `json:"op_entries" yaml:"op_entries"`
	wMtx      sync.Mutex
	written   bool
}

// add an entry to the log writter
func (lw *StandardLogWriter) AddEntry(opEntry OperationEntry) {
	lw.OpEntries = append(lw.OpEntries, opEntry)
}

// PrintLogs - print the logs to a simulation file
func (lw *StandardLogWriter) PrintLogs() {
	lw.wMtx.Lock()
	defer lw.wMtx.Unlock()
	if lw.written { // print once only
		return
	}
	f := createLogFile(lw.Seed)
	defer f.Close()

	for i := range lw.OpEntries {
		writeEntry := fmt.Sprintf("%s\n", (lw.OpEntries[i]).MustMarshal())
		_, err := f.WriteString(writeEntry)
		if err != nil {
			panic("Failed to write logs to file")
		}
	}
	lw.written = true
}

func createLogFile(seed int64) *os.File {
	var f *os.File
	var prefix string
	if seed != 0 {
		prefix = fmt.Sprintf("seed_%10d", seed)
	}
	fileName := fmt.Sprintf("%s--%d.log", prefix, time.Now().UnixNano())
	folderPath := path.Join(os.ExpandEnv("$HOME"), ".simapp", "simulations")
	filePath := path.Join(folderPath, fileName)

	err := os.MkdirAll(folderPath, os.ModePerm)
	if err != nil {
		panic(err)
	}

	f, err = os.Create(filePath)
	if err != nil {
		panic(err)
	}
	fmt.Printf("Logs to writing to %s\n", filePath)

	return f
}

// dummy log writter
type DummyLogWriter struct{}

// do nothing
func (lw *DummyLogWriter) AddEntry(_ OperationEntry) {}

// do nothing
func (lw *DummyLogWriter) PrintLogs() {}
