package service

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gogf/gf/container/gmap"
	"github.com/gogf/gf/encoding/gjson"
	"sparrow/pkg/rpcs"
	"sparrow/pkg/server"
	service2 "sparrow/services/scene-service/internal/service/manager"
	"time"
)

type SceneInfo struct {
	Id            string    `json:"id"`
	Name          string    `json:"name"`
	ConditionDesc string    `json:"condition_desc"`
	ActionDesc    string    `json:"action_desc"`
	Status        int       `json:"status"`
	SceneType     string    `json:"scene_type"`
	Config        string    `json:"config"`
	Action        string    `json:"action"`
	Time          time.Time `json:"time"`
}

type SceneService struct {
	scenes       *gmap.HashMap // 场景ID到场景实例的映射
	timer        TaskManager
	weather      TaskManager
	deviceStatus TaskManager
}

func NewSceneService() *SceneService {
	return &SceneService{
		scenes:       gmap.New(true),
		timer:        service2.NewTimerSceneService(),
		weather:      service2.NewWeatherSceneService(),
		deviceStatus: service2.NewDeviceSceneService(),
	}
}

type TaskManager interface {
	Add(config string) error
	Update(config string) error
	Remove(id string) error
	Start(id string) error
	Stop(id string) error
}

// getServiceByType 根据场景类型获取对应的服务实例
func (m *SceneService) getServiceByType(sceneType string) (TaskManager, error) {
	switch sceneType {
	case "oneKey":
		return nil, nil
	case "timer":
		return m.timer, nil
	case "weather":
		return m.weather, nil
	case "device_status":
		return m.deviceStatus, nil
	default:
		return nil, errors.New("不支持的场景类型: " + sceneType)
	}
}

func (m *SceneService) SubmitAction(args rpcs.ArgsSubmitSceneAction, reply *rpcs.ReplySubmitSceneAction) error {
	scene := SceneInfo{
		Id:            args.Id,
		Name:          args.Name,
		Status:        args.Status,
		ConditionDesc: args.ConditionDesc,
		ActionDesc:    args.ActionDesc,
		SceneType:     args.SceneType,
		Config:        args.Config,
		Action:        args.Action,
		Time:          args.Time,
	}
	srv, err := m.getServiceByType(scene.SceneType)
	if err != nil {
		server.Log.Errorf("不支持的场景类型: %s, 场景ID: %s", scene.SceneType, scene.Id)
		return err
	}
	switch scene.Action {
	case "add":
		err = srv.Add(scene.Config)
		if err != nil {
			return err
		}
		m.scenes.Set(scene.Id, scene)
		return m.saveSceneRedis(scene)
	case "remove":
		err = srv.Remove(scene.Id)
		if err != nil {
			server.Log.Errorf("delete scene error: Id: %s, error: %v\n", scene.Id, err)
		}
		m.scenes.Remove(scene.Id)
		return m.delSceneRedis(scene)
	case "update":
		err = srv.Update(scene.Config)
		if err != nil {
			server.Log.Errorf("update scene error: Id: %s, error: %v\n", scene.Id, err)
			return err
		}
		m.scenes.Set(scene.Id, scene)
		return m.saveSceneRedis(scene)
	case "start":
		err = srv.Start(scene.Id)
		if err != nil {
			server.Log.Errorf("start scene error: Id: %s, error: %v\n", scene.Id, err)
			return err
		}
		scene.Status = 1
		m.scenes.Set(scene.Id, scene)
		return m.updateSceneStatus(scene)
	case "stop":
		err = srv.Stop(scene.Id)
		if err != nil {
			server.Log.Errorf("stop scene error: Id: %s, error: %v\n", scene.Id, err)
			return err
		}
		scene.Status = 0
		m.scenes.Set(scene.Id, scene)
		return m.updateSceneStatus(scene)
	case "do":
		j := gjson.New(scene.Config)
		err = m.doAction(scene.Id, j.GetString("actions"))
	}
	return nil
}

func (m *SceneService) doAction(sceneId, action string) error {
	var actions []*service2.Action
	err := json.Unmarshal([]byte(action), &actions)
	if err != nil {
		server.Log.Errorf("unmarshal actions error :%v", err)
		return err
	}
	err = service2.NewTaskExecutor(actions).Do(sceneId)
	if err != nil {
		server.Log.Errorf("do action error: Id: %s, error: %v", sceneId, err)
	}
	return err
}

func (m *SceneService) saveSceneRedis(scene SceneInfo) error {
	sceneArgs := rpcs.ArgsScene{
		Key:           fmt.Sprintf("scene:%s:%s", scene.SceneType, scene.Id),
		Name:          scene.Name,
		ConditionDesc: scene.ConditionDesc,
		ActionDesc:    scene.ActionDesc,
		SceneId:       scene.Id,
		Config:        scene.Config,
		Time:          scene.Time,
		Status:        scene.Status,
		SceneType:     scene.SceneType,
	}
	sceneReply := rpcs.ReplyEmptyResult{}
	err := server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.SaveScene", sceneArgs, &sceneReply)
	if err != nil {
		server.Log.Errorf("save scene error: Id: %s, error: %v", scene.Id, err)
	}
	return err
}

func (m *SceneService) updateSceneStatus(scene SceneInfo) error {
	sceneArgs := rpcs.ArgsScene{
		Key:    fmt.Sprintf("scene:%s:%s", scene.SceneType, scene.Id),
		Status: scene.Status,
	}
	sceneReply := rpcs.ReplyEmptyResult{}
	err := server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.UpdateSceneStatus", sceneArgs, &sceneReply)
	if err != nil {
		server.Log.Errorf("save scene error: Id: %s, error: %v", scene.Id, err)
	}
	return err
}

func (m *SceneService) delSceneRedis(scene SceneInfo) error {
	sceneArgs := rpcs.ArgsScene{
		Key:    fmt.Sprintf("scene:%s:%s", scene.SceneType, scene.Id),
		Config: scene.Config,
	}
	sceneReply := rpcs.ReplyEmptyResult{}
	err := server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.DeleteScene", sceneArgs, &sceneReply)
	if err != nil {
		server.Log.Errorf("del scene error: Id: %s, error: %v", scene.Id, err)
	}
	return err
}

func (m *SceneService) RestartScenes() {
	sceneArgs := rpcs.ArgsGetAllScene{}
	sceneReply := rpcs.ReplyScenes{}
	err := server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.GetAllScenes", sceneArgs, &sceneReply)
	if err != nil {
		server.Log.Errorf("get all scene error: %v", err)
	}

	reply := rpcs.ReplySubmitSceneAction{}
	for _, v := range sceneReply.Result {
		if v.Status == 1 {
			err = m.SubmitAction(rpcs.ArgsSubmitSceneAction{
				Id:            v.SceneId,
				Name:          v.Name,
				Status:        v.Status,
				ConditionDesc: v.ConditionDesc,
				ActionDesc:    v.ActionDesc,
				SceneType:     v.SceneType,
				Config:        v.Config,
				Action:        "add",
			}, &reply)
		}
	}
}
