package main

import (
	"bytes"
	"fmt"
	"io/fs"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	ics "github.com/arran4/golang-ical"
)

type sheetFields map[string]interface{}

func main() {
	filepath.Walk("/Users/jianlinchen/Downloads/ics_calender", func(path string, info fs.FileInfo, err error) error {
		var calenders []sheetFields
		if info.IsDir() {
			return nil
		}
		log.Println(path)
		fileContent, err := ioutil.ReadFile(path)
		if err != nil {
			panic(err)
		}
		cal, err := ics.ParseCalendar(bytes.NewReader(fileContent))
		if err != nil {
			panic(err)
		}

		keysMap := make(map[string]struct{})
		keys := []string{}

		if len(cal.Components) <= 1 {
			log.Println("path component <= 1", path)
			return nil
		}
		for _, component := range cal.Components[1:] {
			if _, ok := component.(*ics.VEvent); !ok {
				continue
			}

			properties := component.UnknownPropertiesIANAProperties()
			fields := make(sheetFields)
			for _, property := range properties {
				if _, ok := keysMap[property.IANAToken]; !ok {
					keysMap[property.IANAToken] = struct{}{}
					keys = append(keys, property.IANAToken)
				}

				if v, ok := fields[property.IANAToken]; ok {
					switch v.(type) {
					case []string:
						fields[property.IANAToken] = append(fields[property.IANAToken].([]string), property.Value)
					default:
						arr := []string{}
						if v != nil {
							arr = append(arr, v.(string))
						}
						arr = append(arr, property.Value)
						fields[property.IANAToken] = arr
					}
				} else {
					fields[property.IANAToken] = property.Value
				}

				//log.Println(property.IANAToken, " = ", property.Value)
			}
			calenders = append(calenders, fields)
		}

		for i, _ := range calenders {
			cal := calenders[i]
			var timeBegin, timeEnd string
			if _, ok := cal["DTSTART"]; ok {
				timeBegin = cal["DTSTART"].(string)
			}
			if _, ok := cal["DTEND"]; ok {
				timeEnd = cal["DTEND"].(string)
			}
			if timeBegin == "" || timeEnd == "" {
				calenders[i]["DURATION(min)"] = 0
			} else {
				hourbegin, _ := strconv.Atoi(strings.Trim(timeBegin[9:], "Z"))
				hourend, _ := strconv.Atoi(strings.Trim(timeEnd[9:], "Z"))
				sub := hourend - hourbegin
				useTime := sub / 10000 * 60
				extra := 0
				if sub%10000/100 >= 60 {
					extra = 40
				}
				useTime += sub%10000/100 - extra

				calenders[i]["DURATION(min)"] = useTime
			}
		}
		keys = append(keys, "DURATION(min)")

		f, _ := os.Create(fmt.Sprintf("./ics/output/%s", strings.TrimRight(info.Name(), ".ics")+".csv"))
		for i, key := range keys {
			if i-1 != len(keys) {
				f.WriteString(strconv.Quote(key) + ",")
			} else {
				f.WriteString(strconv.Quote(key))
			}
		}
		f.WriteString("\n")
		for _, fields := range calenders {
			ss := strings.Builder{}
			for i, key := range keys {
				v, _ := fields[key]
				switch v.(type) {
				case string:
					ss.WriteString(strconv.Quote(strings.Replace(v.(string), ",", "，", -1)))
				case []string:
					ss.WriteString(strconv.Quote(strings.Join(v.([]string), "|")))
				case int:
					ss.WriteString(strconv.Quote(strconv.Itoa(v.(int))))
				}
				if i != len(keys)-1 {
					ss.WriteByte(',')
				} else {
					ss.WriteByte('\n')
				}
			}
			f.WriteString(ss.String())
		}
		f.Close()

		return nil
	})
}
