package service

import (
	deviceService "iot_manager_service/app/device/service"
	"iot_manager_service/app/multimedia/dao"
	"iot_manager_service/app/multimedia/model"
	"iot_manager_service/app/system/service"
	"iot_manager_service/util/common"
	"iot_manager_service/util/logger"
	"time"
)

var ProgramService = new(programService)

type programService struct{}

func (s *programService) Get(id int) (*dao.Program, *common.Errors) {
	Program := &dao.Program{
		ID: id,
	}
	err := Program.Get()
	if err != nil {
		return nil, common.FailResponse(err.Error(), nil)
	}
	return Program, nil
}

func (s *programService) List(tenantId string, searchValue string, current, size, sysType int) ([]model.ProgramDetail, int64,
	*common.Errors) {
	program := &dao.Program{
		TenantId: tenantId,
	}
	offset := (current - 1) * size
	limit := size
	if searchValue != "" {
		program.Name = searchValue
	}
	if sysType != -1 {
		program.SysType = sysType
	}

	programs, total, err := program.GetPrograms(offset, limit)
	if err != nil {
		return nil, 0, common.FailResponse(err.Error(), nil)
	}
	var rsp []model.ProgramDetail
	for _, pro := range programs {
		rsp = append(rsp, model.ProgramDetail{
			Program:        pro,
			ResolutionName: service.DictService.GetResolutionName(tenantId, pro.Resolution),
		})
	}
	return rsp, total, nil
}

func (s *programService) Remove(userId int64, tenantId string, id int) *common.Errors {
	relation := &dao.ProgramRelation{
		ProgramId: id,
		TenantId:  tenantId,
		IsDeleted: 1,
	}
	err := relation.Delete()
	if err != nil {
		return common.FailResponse(err.Error(), nil)
	}

	program := &dao.Program{
		ID:         id,
		IsDeleted:  1,
		UpdateUser: userId,
		UpdateTime: time.Now(),
	}
	err = program.Delete()
	if err != nil {
		return common.FailResponse(err.Error(), nil)
	}
	service.OperationHisService.Save(userId, tenantId, common.OperationRemove, common.ModuleTypeInfoBar,
		common.DeviceTypeDefault, "", common.OperationSuccess)
	return nil
}

func (s *programService) GetList(tenantId string, name string) ([]dao.Program, *common.Errors) {
	Program := &dao.Program{
		TenantId: tenantId,
		Name:     name,
	}
	libraries, err := Program.GetAll()
	if err != nil {
		return nil, common.FailResponse(err.Error(), nil)
	}

	return libraries, nil
}

func (s *programService) Submit(tenantId string, userId int64, req model.ReqProgramSubmit) *common.Errors {
	program := &dao.Program{
		Name:        req.Name,
		Resolution:  req.Resolution,
		Duration:    req.Duration,
		FileSize:    req.FileSize,
		ImgDuration: req.ImgDuration,
		Remarks:     req.Remarks,
		SysType:     req.SysType,
		TenantId:    tenantId,
		CreateTime:  time.Now(),
		CreateUser:  userId,
		UpdateTime:  time.Now(),
		UpdateUser:  userId,
		IsDeleted:   0,
	}
	if err := program.Create(); err != nil {
		logger.Logger.Errorf("Create err = %s \n", err.Error())
		return common.FailResponse(err.Error(), nil)
	}

	libraryIds := common.StringToIntArray(req.LibraryIds)
	for index, libraryId := range libraryIds {
		relation := &dao.ProgramRelation{
			ProgramId: program.ID,
			LibraryId: libraryId,
			OrderNo:   index + 1,
			TenantId:  tenantId,
			IsDeleted: 0,
			Duration:  req.ImgDuration,
		}
		err := relation.Save()
		if err != nil {
			logger.Logger.Errorf("relation save err = %s \n", err.Error())
			_ = program.Remove()
			_ = relation.Remove()
			return common.FailResponse(err.Error(), nil)
		}
	}

	service.OperationHisService.Save(userId, tenantId, common.OperationCreate, common.ModuleTypeInfoBar,
		common.DeviceTypeDefault, program.Name, common.OperationSuccess)
	return common.SuccessResponse(common.Succeeded, nil)
}

func (s *programService) GetLibraryList(tenantId string, programId int) ([]dao.Library, *common.Errors) {
	relation := &dao.ProgramRelation{
		ProgramId: programId,
		TenantId:  tenantId,
	}
	relations, err := relation.GetByProgram()
	if err != nil {
		logger.Logger.Errorf("relation BatchCreate err = %s \n", err.Error())
		return nil, common.FailResponse(err.Error(), nil)
	}

	var libraryIds []int
	for _, relation := range relations {
		libraryIds = append(libraryIds, relation.LibraryId)
	}
	//fmt.Printf("libraryIds = %v", libraryIds)
	library := &dao.Library{TenantId: tenantId}
	libraries, err := library.GetLibrariesByIds(libraryIds)
	for i, librarie := range libraries {
		//fmt.Printf("relations = %v \n", relations)
		//fmt.Printf("librarie = %v \n", librarie)
		if librarie.LibDuration == 0 {
			libraries[i].LibDuration = 3 //图片默认给个3秒
		}
		libraries[i].LibDuration = libraries[i].LibDuration * 1000
	}
	if err != nil {
		logger.Logger.Errorf("GetLibrariesByIds err = %s \n", err.Error())
		return nil, common.FailResponse(err.Error(), nil)
	}
	return libraries, nil
}

func (s *programService) RelationDeviceList(tenantId string, sysType, resolution int) ([]model.ProgramDeviceDetail,
	*common.Errors) {
	var lampGroupIds []int
	infoBoardMap := make(map[int][]model.ProgramDevice)
	if sysType == model.SysTypeInfoBar {
		infoBoardDevices := deviceService.InfoBoardService.GetByResolution(tenantId, resolution)
		for _, device := range infoBoardDevices {
			lampGroupIds = append(lampGroupIds, device.GroupId)
			programDevice := model.ProgramDevice{
				Id:         device.ID,
				PublicName: device.InfoName,
			}
			if devices, isExist := infoBoardMap[device.GroupId]; isExist {
				devices = append(devices, programDevice)
				infoBoardMap[device.GroupId] = devices
			} else {
				infoBoardMap[device.GroupId] = []model.ProgramDevice{programDevice}
			}
		}
	} else if sysType == model.SysTypeBroadcast {
		ipBroadcastDevices := deviceService.IpBroadcastService.GetAll(tenantId)
		for _, device := range ipBroadcastDevices {
			lampGroupIds = append(lampGroupIds, device.GroupId)
			programDevice := model.ProgramDevice{
				Id:         device.ID,
				PublicName: device.CastName,
			}
			if devices, isExist := infoBoardMap[device.GroupId]; isExist {
				devices = append(devices, programDevice)
				infoBoardMap[device.GroupId] = devices
			} else {
				infoBoardMap[device.GroupId] = []model.ProgramDevice{programDevice}
			}
		}
	} else {
		return nil, nil
	}

	lampPoleGroups := deviceService.LampPoleGroupService.GetByIds(tenantId, lampGroupIds)
	var details []model.ProgramDeviceDetail
	for _, lampPoleGroup := range lampPoleGroups {
		details = append(details, model.ProgramDeviceDetail{
			PublicName:    lampPoleGroup.PoleGroupName,
			InfoBoardList: infoBoardMap[lampPoleGroup.ID],
		})
	}
	return details, nil
}

func (s *programService) RelationDeviceListByIds(tenantId string, sysType int, deviceIds string) ([]model.ProgramDeviceList,
	*common.Errors) {
	deviceList := []model.ProgramDeviceList{}
	if sysType == model.SysTypeInfoBar {
		infoBoardDevices := deviceService.InfoBoardService.GetByIds(tenantId, deviceIds)
		//fmt.Printf("infoBoardDevices = %v", infoBoardDevices)
		for _, device := range infoBoardDevices {
			deviceList = append(deviceList, model.ProgramDeviceList{
				DeviceName:   device.InfoName,
				LampPoleName: device.LampPoleName,
				Address:      device.IPAddress,
			})
		}
	} else if sysType == model.SysTypeBroadcast {
		ipBroadcastDevices := deviceService.IpBroadcastService.GetByIds(tenantId, deviceIds)
		for _, device := range ipBroadcastDevices {
			group, _ := deviceService.LampPoleGroupService.Get(device.GroupId)
			deviceList = append(deviceList, model.ProgramDeviceList{
				DeviceName:   device.CastName,
				LampPoleName: group.PoleGroupName,
				Address:      device.IPAddress,
			})
		}
	} else {
		return nil, nil
	}
	return deviceList, nil
}
