package server

import (
	"common/log"
	"common/proto/sc/sc_pb"
	"common/proto/ss/grpc_pb"
	"context"
	"google.golang.org/protobuf/proto"
	instance2 "scene/internal/instance"
	"sync"
)

func (s *Server) Enter(ctx context.Context, req *grpc_pb.EnterReq) (*grpc_pb.EnterResp, error) {
	var i *instance2.Instance
	if len(instance2.Mgr.GetAll()) == 0 {
		i = instance2.NewScene(s.SID, req.InstanceID)
		i.Start(s.EtcdTTL)
	} else {
		for _, v := range instance2.Mgr.GetAll() {
			i = v
			break
		}
	}
	i.EventIn <- req

	payload, _ := proto.Marshal(&sc_pb.S2C_EnterInstance{
		Info: &sc_pb.PositionInfo{
			USN: req.USN,
			X:   1,
			Y:   1,
		},
	})
	return &grpc_pb.EnterResp{
		SceneSID:  s.SID,
		UniqueNo:  i.UniqueNo,
		MessageID: int32(sc_pb.MessageID_MESSAGE_ID_ENTER_INSTANCE),
		Payload:   payload,
	}, nil
}

func (s *Server) Leave(ctx context.Context, req *grpc_pb.LeaveReq) (*grpc_pb.LeaveResp, error) {
	if i := instance2.Mgr.GetByUniqueNo(req.UniqueNo); i != nil {
		i.EventIn <- req
	}
	return &grpc_pb.LeaveResp{}, nil
}

func (s *Server) Action(server grpc_pb.Scene_ActionServer) error {
	wg := &sync.WaitGroup{}
	wg.Add(1)
	go func() {
		defer wg.Done()
		defer func() {
			if err := recover(); err != nil {
				log.Errorf("Action panic: %v", err)
			}
		}()
		for {
			if args, err := server.Recv(); err != nil {
				return
			} else {
				if ins := instance2.Mgr.GetByUniqueNo(args.UniqueNo); ins != nil {
					select {
					case ins.EventIn <- args:
					default:
						log.Warnf("instance event in full: %v, %v", ins.InstanceID, ins.UniqueNo)
					}
				}
			}
		}
	}()
	wg.Wait()
	return server.SendAndClose(&grpc_pb.ActionResp{})
}
