package client

import (
	"fmt"
	"time"

	gerr "galaxy/error"
)

var (
	checkConnectionInterval = 5 * time.Second
	checkVersionInterval    = time.Hour
	statePersistInterval    = time.Second
)

func (e *client) startBackground() {
	if e.conn == nil || e.updater == nil {
		return
	}

	go e.backgroundLoop()
}

func (e *client) stopBackground() {
	e.backgroundOnce.Do(func() {
		close(e.backgroundStop)
	})
}

func (e *client) backgroundLoop() {
	checkConnTimer := time.NewTimer(checkConnectionInterval)
	checkVersionTimer := time.NewTimer(checkVersionInterval)
	persistStateTimer := time.NewTimer(statePersistInterval)
	defer func() {
		checkConnTimer.Stop()
		checkVersionTimer.Stop()
		persistStateTimer.Stop()
	}()

	for {
		select {
		case <-e.backgroundStop:
			return
		case <-checkConnTimer.C:
			if e.conn != nil {
				e.OnConnection(e.conn.CheckConnection())
			}
			checkConnTimer.Reset(checkConnectionInterval)
		case <-checkVersionTimer.C:
			if e.updater != nil {
				if err := e.updater.CheckAndPrepareLatest(); err != nil {
					e.handlerError(err)
				}
			}
			checkVersionTimer.Reset(checkVersionInterval)
		case <-persistStateTimer.C:
			e.ensureStatePersist()
			persistStateTimer.Reset(statePersistInterval)
		}
	}
}

func (e *client) ensureStatePersist() {
	param := e.GetParams()
	needSaving := false
	e.stateMu.Lock()
	if e.world != nil {
		if param.CameraZoom > 0 && param.CameraZoom != e.state.CameraZoom {
			e.state.CameraZoom = param.CameraZoom
			needSaving = true
		}
		if param.CameraXWorldFp != e.state.CameraXFp {
			e.state.CameraXFp = param.CameraXWorldFp
			needSaving = true
		}
		if param.CameraYWorldFp != e.state.CameraYFp {
			e.state.CameraYFp = param.CameraYWorldFp
			needSaving = true
		}
	}
	if e.mapSplitter != nil && e.mapSplitter.Offset != e.state.MapSplitterOffset {
		e.state.MapSplitterOffset = e.mapSplitter.Offset
		needSaving = true
	}
	if e.accInfo.Open != e.state.AccordionInfoOpen {
		e.state.AccordionInfoOpen = e.accInfo.Open
		needSaving = true
	}
	if e.accCalc.Open != e.state.AccordionCalcOpen {
		e.state.AccordionCalcOpen = e.accCalc.Open
		needSaving = true
	}
	if needSaving {
		if err := e.s.SaveState(*e.state); err != nil {
			e.handlerError(err)
		}
	}
	e.stateMu.Unlock()
}

func (e *client) handlerError(err error) {
	if err == nil {
		return
	}

	fmt.Printf("ERROR: %s\n", err)

	switch {
	case gerr.IsConnection(err):
		e.OnConnectionError(err)
	case gerr.IsStorage(err):
		e.OnStorageError(err)
	default:
		e.OnServiceError(err)
	}
}
