package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	"git.nils.zone/nils/prettify"
)

type lineEntry struct {
	BlockHeight int
	BlockHash   string
	Type        string
	PoolID      int
	Time        time.Time
	Amounts     map[string]float64
}

func main() {
	// define flags
	csvFile := flag.String("csvFile", "", "specifies the path the csv file containing the transaction log")
	flag.Parse()
	if *csvFile == "" {
		log.Fatal("please specify a csvFile using the flag -csvFile")
	}

	// start of program
	b, err := readCSV(*csvFile)
	if err != nil {
		log.Fatalf("error occurred when reading csv, error is: %s", err)
	}
	entries, err := unmarshalCSV(b)
	if err != nil {
		panic(err)
	}

	var rewards []lineEntry
	for i := range entries {
		if entries[i].Type == "Rewards" {
			rewards = append(rewards, entries[i])
		}
	}

	// print out all rewards
	printRewards(rewards)
}

func printRewards(rewards []lineEntry) {
	// daily
	daily := listRewards("2006-01-02", rewards)

	// monthly
	monthly := listRewards("2006-01", rewards)

	// yearly
	yearly := listRewards("2006", rewards)

	// print rewards
	log.Println("listing daily Rewards")
	prettify.Print(daily)
	log.Println("listing monthly Rewards")
	prettify.Print(monthly)
	log.Println("listing yearly Rewards")
	prettify.Print(yearly)
}

func listRewards(format string, entries []lineEntry) map[string]float64 {
	rewards := make(map[string]float64)
	for i := range entries {
		rewardsString := entries[i].Time.Format(format)
		rewards[rewardsString] += entries[i].Amounts["DFI"]
	}
	return rewards
}

func readCSV(filename string) ([]byte, error) {
	b, err := os.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return b, nil
}

func unmarshalCSV(b []byte) ([]lineEntry, error) {
	// output variable
	var e []lineEntry

	// read all lines and do magic on each line
	lines := strings.Split(string(b), "\n")
	// for i := range lines {
	for i := 1; i < len(lines); i++ {
		// create variable for current line
		var l lineEntry
		l.Amounts = make(map[string]float64)

		// Remove " from lines
		line := strings.ReplaceAll(lines[i], `"`, ``)

		// split line by comma
		entries := strings.Split(line, ",")

		// convert blockHeight to int
		height, err := strconv.Atoi(entries[0])
		if err != nil {
			return nil, fmt.Errorf("can't convert blockHeight in line %d to int, error is: %s", i+1, err)
		}

		// get time from CSV
		dateTime, err := time.Parse("02/01/2006 / 03:04 pm", entries[2])
		if err != nil {
			return nil, fmt.Errorf("can't convert time in line %d to time.time, error is: %s", i+1, err)
		}

		// convert poolID to int
		if entries[5] == "" {
			// empty row
			entries[5] = "0"
		}
		poolID, err := strconv.Atoi(entries[5])
		if err != nil {
			return nil, fmt.Errorf("can't convert poolID in line %d to int, error is: %s", i+1, err)
		}

		// Split for amount and currency
		amounts := strings.Split(strings.Join(entries[6:], " "), " ")
		for i := range amounts {
			// Split amounts and currency
			ac := strings.Split(amounts[i], "@")
			amountString := ac[0]
			currency := ac[1]
			// Parse string to float
			amount, err := strconv.ParseFloat(amountString, 64)
			if err != nil {
				return nil, err
			}

			// put rewards into map
			l.Amounts[currency] = amount
		}

		// fill l with values
		l.BlockHeight = height   // entries[0]
		l.BlockHash = entries[1] // entries[1]
		l.Type = entries[4]      // entries[2]
		l.PoolID = poolID        // entries[3]
		l.Time = dateTime

		e = append(e, l)
	}
	return e, nil
}