const movingThings = require('shinobi-node-moving-things-tracker').Tracker
module.exports = (s,config,lang) => {
    const objectTrackers = {}
    const objectTrackerTimeouts = {}
    function resetObjectTracker(trackerId,matrices){
        const Tracker = movingThings.newTracker();
        objectTrackers[trackerId] = {
            frameCount: 1,
            tracker: Tracker,
            lastPositions: []
        }
        return objectTrackers[trackerId]
    }
    function setLastTracked(trackerId, trackedMatrices){
        const theTracker = objectTrackers[trackerId]
        theTracker.lastPositions = trackedMatrices
    }
    function getTracked(trackerId){
        const theTracker = objectTrackers[trackerId]
        const frameCount = theTracker.frameCount
        const trackedObjects = theTracker.tracker.getJSONOfTrackedItems().map((matrix) => {
            return {
                id: matrix.id,
                tag: matrix.name,
                x: matrix.x,
                y: matrix.y,
                width: matrix.w,
                height: matrix.h,
                confidence: matrix.confidence,
                isZombie: matrix.isZombie,
            }
        })
        return trackedObjects;
    }
    function trackObject(trackerId,matrices){
        if(!objectTrackers[trackerId]){
            resetObjectTracker(trackerId)
        }
        const mappedMatrices = matrices.map((matrix) => {
            return {
                x: matrix.x,
                y: matrix.y,
                w: matrix.width,
                h: matrix.height,
                confidence: matrix.confidence,
                name: matrix.tag,
            }
        });
        const theTracker = objectTrackers[trackerId]
        theTracker.tracker.updateTrackedItemsWithNewFrame(mappedMatrices, theTracker.frameCount);
        ++theTracker.frameCount
    }
    function clearTracker(trackerId){
        objectTrackers[trackerId].tracker.reset()
        delete(objectTrackers[trackerId])
        delete(objectTrackerTimeouts[trackerId])
        clearTimeout(objectTrackerTimeouts[trackerId]);
    }
    function trackObjectWithTimeout(trackerId,matrices){
        clearTimeout(objectTrackerTimeouts[trackerId]);
        objectTrackerTimeouts[trackerId] = setTimeout(() => {
            clearTracker(trackerId)
        },1000 * 60);
        trackObject(trackerId,matrices);
    }
    function objectHasMoved(matrices, options = {}) {
      const { imgHeight = 1, imgWidth = 1, threshold = 0 } = options;
      for (let i = 0; i < matrices.length; i++) {
        const current = matrices[i];
        if (i < matrices.length - 1) {
          const next = matrices[i + 1];
          let totalDistanceMoved = 0;
          let numPointsCompared = 0;
          if (next) {
            // Compare each corner of the matrices
            const currentCorners = [
              { x: current.x, y: current.y },
              { x: current.x + current.width, y: current.y },
              { x: current.x, y: current.y + current.height },
              { x: current.x + current.width, y: current.y + current.height }
            ];
            const nextCorners = [
              { x: next.x, y: next.y },
              { x: next.x + next.width, y: next.y },
              { x: next.x, y: next.y + next.height },
              { x: next.x + next.width, y: next.y + next.height }
            ];
            for (let j = 0; j < currentCorners.length; j++) {
              const currentCorner = currentCorners[j];
              const nextCorner = nextCorners[j];
              const dx = nextCorner.x - currentCorner.x;
              const dy = nextCorner.y - currentCorner.y;
              const distanceMoved = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
              const distanceMovedPercent =
                (100 * distanceMoved) / Math.max(current.width, current.height);
              totalDistanceMoved += distanceMovedPercent;
              numPointsCompared++;
            }
            const averageDistanceMoved = totalDistanceMoved / numPointsCompared;
            if (averageDistanceMoved < threshold) {
              continue;
            } else {
              return true;
            }
          }
        }
      }
      return false;
    }
    function groupMatricesById(matrices) {
      const matrixById = {};
      const matrixTags = {};

      matrices.forEach(matrix => {
        const id = matrix.id;
        const tag = matrix.tag;
        if (!matrixById[id]) {
          matrixById[id] = [];
        }
        matrixTags[tag] = id;
        matrixById[id].push(matrix);
      });

      return matrixById
    }
    function getAllMatricesThatMoved(monitorConfig,matrices){
        const monitorDetails = monitorConfig.details
        const imgWidth = parseInt(monitorDetails.detector_scale_x_object) || 1280
        const imgHeight = parseInt(monitorDetails.detector_scale_y_object) || 720
        const objectMovePercent = parseInt(monitorDetails.detector_object_move_percent) || 5
        const groupKey = monitorConfig.ke
        const monitorId = monitorConfig.mid
        const trackerId = `${groupKey}${monitorId}`
        const theTracker = objectTrackers[trackerId]
        const lastPositions = theTracker.lastPositions
        const sortedById = groupMatricesById([...lastPositions,...matrices])
        const movedMatrices = []
        for (const objectId in sortedById) {
            const sortedList = sortedById[objectId]
            if(sortedList[1]){
                const matrixHasMoved = objectHasMoved(sortedList,{
                    threshold: objectMovePercent,
                    imgWidth: imgWidth,
                    imgHeight: imgHeight,
                });
                if(matrixHasMoved){
                    movedMatrices.push(sortedList[1])
                }
            }
        }
        return movedMatrices
    }
    return {
        trackObjectWithTimeout,
        resetObjectTracker,
        clearTracker,
        trackObject,
        getTracked,
        setLastTracked,
        getAllMatricesThatMoved,
    }
}
