export interface PositionUpdate {
    objects: Agent[]
    type: NotificationType
}

export interface Agent {
    id: string
    sensorId: string
    type: AgentType
    sensorType: SensorType
    position: Position
    orientation?: Quaternion
    lastPosUpdate: string
    zoneDescriptors: ZoneDesc[]
    extractedAttributes?: ExtAttribute
    [x: string]: any
}

export interface Position {
    refSystemId: string
    point: WGS84 | RelativePos
    accuracy?: number
}

export interface WGS84 {
    latitude: number
    longitude: number
    altitude?: number
}

export interface RelativePos {
    x: number
    y: number
    z?: number
}

export interface ZoneDesc {
    zoneId: string
    notificationType: NotificationType
}

export interface Quaternion {
    x: number
    y: number
    z: number
    w: number
}

export enum NotificationType {
    "EntryNotification",
    "ExitNotification", 
    "Unknown"
}

enum AgentType {
    "HUMAN",
    "BOX",
    "ROBOT"
}

enum SensorType {
    "UWB",
    "Bluetooth",
    "WiFi"
}
interface ExtAttribute {
    batteryChargeLevel: number
    loadedItems: number[]
    errors: number[]
    theta: number
} 


export function validateTypePosition(obj: any) {
    if (!isPosition(obj)) {
        throw new TypeError("Unvalid Position")  
    }
}
  
export function validateTypeAgent(obj: any) {
    if (!isAgent(obj)) {
        throw new TypeError("Unvalid Agent: " + Object.keys(obj))  
    }
}


// --- Type Guards

function isWGS84(obj: any): obj is WGS84 {
    return obj
        && "latitude" in obj
        && "longitude" in obj
} 

function isRelativePos(obj: any): obj is RelativePos {
    return obj
        && "x" in obj 
        && "y" in obj
} 

export function isPosition(obj: any): obj is Position {
    return isWGS84(obj.point) || isRelativePos(obj.point)
} 

export function isAgent(obj: any): obj is Agent {
    return obj
        && "id" in obj
        && "position" in obj
        && isPosition(obj.position)
} 


// --- Way points

export interface WayPoint {
    agentId: string
    agentType?: AgentType
    publisher?: string
    position: Position
    time: string
}


export function isWayPoint(obj: any): obj is WayPoint {
    return obj
        && "agentId" in obj
        && "time" in obj
        && isPosition(obj.position)
}