package meterFirm

import (
	"encoding/json"
	"log"
	"os"
	"path/filepath"
	"sync"

	g "tgk-touch/internal/global"
	"tgk-touch/internal/library/meterControl"

	"github.com/towgo/towgo/lib/system"
	"github.com/towgo/towgo/towgo"
)

type MeterFirmManager struct {
	mu        sync.RWMutex
	meterFirm string
	onReload  []func()
}

type MeterFirmData struct {
	MeterFirm string `json:"meter_firm"`
}

var (
	manager *MeterFirmManager = &MeterFirmManager{}
)

func Manager() *MeterFirmManager {
	return manager
}

func getMeterFirmFilePath() string {
	return filepath.Join(system.GetPathOfProgram(), "data", "meterFirm.json")
}

func (m *MeterFirmManager) Get() string {
	m.mu.RLock()
	defer m.mu.RUnlock()
	return m.meterFirm
}

func (m *MeterFirmManager) Set(firm string) error {
	m.mu.Lock()
	m.meterFirm = firm
	if err := m.saveToFile(); err != nil {
		m.mu.Unlock()
		return err
	}

	cbs := m.onReload
	m.mu.Unlock()

	for _, cb := range cbs {
		cb()
	}
	return nil
}

func (m *MeterFirmManager) RegisterReloadCallback(cb func()) {
	m.mu.Lock()
	defer m.mu.Unlock()
	m.onReload = append(m.onReload, cb)
}

func (m *MeterFirmManager) saveToFile() error {
	filePath := getMeterFirmFilePath()
	dir := filepath.Dir(filePath)
	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}

	data := MeterFirmData{
		MeterFirm: m.meterFirm,
	}

	jsonData, err := json.Marshal(data)
	if err != nil {
		return err
	}

	return os.WriteFile(filePath, jsonData, 0600)
}

func (m *MeterFirmManager) loadFromFile() error {
	m.mu.Lock()
	defer m.mu.Unlock()

	filePath := getMeterFirmFilePath()
	jsonData, err := os.ReadFile(filePath)
	if err != nil {
		if os.IsNotExist(err) {
			m.meterFirm = g.Config().DeviceInfo.MeterFirm
			return m.saveToFile()
		}
		return err
	}

	var data MeterFirmData
	if err := json.Unmarshal(jsonData, &data); err != nil {
		return err
	}

	if data.MeterFirm == "" {
		data.MeterFirm = g.Config().DeviceInfo.MeterFirm
	}

	m.meterFirm = data.MeterFirm
	return nil
}

func (m *MeterFirmManager) GetMeterControl() meterControl.IMeterControl {
	return meterControl.GetMeterControls(meterControl.MeterFirm(m.Get()))
}

func Init() {

	if err := manager.loadFromFile(); err != nil {
		g.GVA_LOG.Sugar().Warnf("load meterFirm data failed: %v, using default", err)
		manager.meterFirm = g.Config().DeviceInfo.MeterFirm
		log.Println("===========", g.Config().DeviceInfo.MeterFirm)
		err = manager.saveToFile()
		if err != nil {
			panic(err)
		}
	}

	towgo.SetFunc("/m9z/meter/getMeterFirm", getMeterFirm)
	towgo.SetFunc("/m9z/meter/setMeterFirm", setMeterFirm)
}

func getMeterFirm(rpcConn towgo.JsonRpcConnection) {
	rpcConn.WriteResult(map[string]interface{}{
		"meter_firm": manager.Get(),
	})
}

type SetMeterFirmReq struct {
	MeterFirm string `json:"meter_firm"`
}

func setMeterFirm(rpcConn towgo.JsonRpcConnection) {
	var req SetMeterFirmReq
	rpcConn.ReadParams(&req)
	if req.MeterFirm == "" {
		rpcConn.WriteError(400, "meter_firm is required")
		return
	}
	_, ok := meterControl.MeterFirms[req.MeterFirm]
	if !ok {
		rpcConn.WriteError(400, "invalid meter_firm, available: ADL400, DDSD1352, DTS1352")
		return
	}
	if err := manager.Set(req.MeterFirm); err != nil {
		rpcConn.WriteError(500, "save meter_firm failed: "+err.Error())
		return
	}
	rpcConn.WriteResult(map[string]interface{}{
		"success":    true,
		"meter_firm": req.MeterFirm,
	})
}
