package main

import (
	"context"
	"fmt"
	"gotool/excel"
	"io/ioutil"
	"os"
	"strings"

	"github.com/panjf2000/ants/v2"
	wailsRuntime "github.com/wailsapp/wails/v2/pkg/runtime"
	"gopkg.in/ini.v1"
)

const (
	IniConfigFileName = "config.ini"
	IniConfigSection  = "default"
)

type ConvertFileInfo struct {
	IsDay       bool
	PngFilePath string
	NewFileName string
}

// App struct
type App struct {
	ctx        context.Context
	Pool       *ants.Pool
	Config     excel.IniConfig
	ConfigFile *ini.File
}

// NewApp creates a new App application struct
func NewApp() *App {
	return &App{}
}

// startup is called when the app starts. The context is saved
// so we can call the runtime methods
func (a *App) startup(ctx context.Context) {
	a.ctx = ctx
	wailsRuntime.WindowSetDarkTheme(a.ctx)
}

func (a *App) domready(ctx context.Context) {
	// read and emit setting
	var err error
	a.ConfigFile, err = ini.Load(IniConfigFileName)
	if err != nil {
		a.ConfigFile = ini.Empty()
	}
	a.ConfigFile.Section(IniConfigSection).MapTo(&a.Config)
	wailsRuntime.EventsEmit(a.ctx, "setting", a.Config)
}

// save config
func (a *App) shutdown(ctx context.Context) {
	a.ConfigFile.Section(IniConfigSection).ReflectFrom(&a.Config)
	a.ConfigFile.SaveTo(IniConfigFileName)
}

// style is Convert / Combine
func (a *App) OpenDirectoryDialog(style string) string {
	var dialogOptions wailsRuntime.OpenDialogOptions
	path, _ := wailsRuntime.OpenDirectoryDialog(a.ctx, dialogOptions)
	if path != "" {
		if style == "Convert" {
			a.Config.ConvertFolderPath = path
		} else if style == "Combine" {
			a.Config.CombineFolderPath = path
		}
	}

	return path
}

func (a *App) OpenFileDialog() string {
	var dialogOptions wailsRuntime.OpenDialogOptions
	path, _ := wailsRuntime.OpenFileDialog(a.ctx, dialogOptions)

	if path != "" {
		a.Config.ExcelFilePath = path
	}

	return path
}

func (a *App) Convert(filePath string, folderPath string, dayTime []string, lightType []string) {
	a.Config.DayTime = dayTime
	a.Config.LightType = lightType

	mexcel, err := excel.OpenFile(filePath)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	// calc and emit processing
	go a.CalcProcessing(mexcel)

	// count all png image
	var filesInfo []ConvertFileInfo
	var info ConvertFileInfo
	var taskTotal uint16 = 0
	for _, d := range dayTime {
		isDay := true
		newFolderPath := ""
		// dayTime = "Day" | "Night"
		if d == excel.ModeNight {
			isDay = false
			newFolderPath = folderPath + "_" + excel.ModeNight
		} else if d == excel.ModeDay {
			isDay = true
			newFolderPath = folderPath + "_" + excel.ModeDay
		} else {
			continue
		}
		os.Mkdir(newFolderPath, os.ModePerm)

		files, err := ioutil.ReadDir(folderPath)
		if err != nil {
			fmt.Println("Error:", err)
			return
		}

		// calc total gorout
		for _, file := range files {
			newFileName := newFolderPath + "\\" + file.Name()
			if strings.Contains(newFileName, ".png") && !strings.Contains(newFileName, ".bmp") && !strings.Contains(newFileName, ".bin") {
				info.IsDay = isDay
				info.NewFileName = newFileName
				info.PngFilePath = folderPath + "\\" + file.Name()
				filesInfo = append(filesInfo, info)
				taskTotal += 3 // 3 task: CreateBmp("CHL"),CreateBmp("RCL"),CreateBin("isDay")
			}
		}
	}

	// send total task count
	mexcel.ChTaskAdd <- taskTotal

	// convert all png file
	for _, file := range filesInfo {
		a.Pool.Submit(TaskCreateBmp(mexcel, file, "CHL"))
		a.Pool.Submit(TaskCreateBmp(mexcel, file, "RCL"))
		a.Pool.Submit(TaskCreateBin(mexcel, file))
	}
}

func TaskCreateBmp(mexcel *excel.MExcel, file ConvertFileInfo, cmd string) func() {
	return func() {
		mexcel.CreateBmp(file.PngFilePath, file.NewFileName, cmd)
	}
}

func TaskCreateBin(mexcel *excel.MExcel, file ConvertFileInfo) func() {
	return func() {
		mexcel.CreateBin(file.PngFilePath, file.NewFileName, file.IsDay)
	}
}

func (a *App) Combine(filePath string, folderPath string) {
	mexcel, err := excel.OpenFile(filePath)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	// calc and emit processing
	go a.CalcProcessing(mexcel)

	mexcel.ListBinFiles(folderPath)
	mexcel.CreateFlashBin(folderPath + "\\combine.bin")
}

func (a *App) CalcProcessing(mexcel *excel.MExcel) {
	var currentCnt uint32 = 0
	var totalCnt uint32 = 0
	var percent uint8 = 0
	for {
		select {
		case done := <-mexcel.ChDone:
			if done {
				return
			} else {
				currentCnt = 0
				totalCnt = 0
				percent = 0
			}
		case <-mexcel.ChOneTaskFinished:
			if totalCnt != 0 {
				currentCnt++
				currentPercent := uint8(currentCnt * 100 / totalCnt)
				if percent != currentPercent {
					percent = currentPercent
					wailsRuntime.EventsEmit(a.ctx, "processing", percent)
				}
			}
		case taskAdd := <-mexcel.ChTaskAdd:
			totalCnt += uint32(taskAdd)
		}
	}
}
