'use strict';
angular.module('beamng.apps')
.directive('gooseDataLogger', ['$timeout', function($timeout) {
  return {
    template: '<object style="width:100%; height:100%;" type="image/svg+xml" data="/ui/modules/apps/DataLogger/DataLogger.svg"></object>',
    replace: true,
    restrict: 'EA',
    link: function(scope, element, attrs) {
      const localStorageKey = 'loggerData';

      // Unit systems for metric only
      const unitSystems = {
        metric: {
          speedFactor: 1, // m/s to meters
          label: 'meters'
        }
      };

      // Always use metric system
      scope.units = unitSystems.metric;
      scope.goalEnd_330ft = 100.5;    // 330 feet in meters
      scope.goalEnd_60ft = 18.2;      // 60 feet in meters
      scope.goalEnd_660ft = 201;      // 660 feet in meters
      scope.goalEnd_1000ft = 304;     // 1000 feet in meters
      scope.goalEnd_1320ft = 402;     // 1320 feet in meters (1/4 mile)

      function saveData() {
        const data = {
          rpmData,
          wpData,
          asData,
          tpsData,
          psiData,
          gearData,
          gforceData,
          currentX // Save the vertical line position
        };
        localStorage.setItem(localStorageKey, JSON.stringify(data));
      }

      function loadData() {
        const data = JSON.parse(localStorage.getItem(localStorageKey));
        if (data) {
          rpmData = data.rpmData || [];
          wpData = data.wpData || [];
          asData = data.asData || [];
          tpsData = data.tpsData || [];
          psiData = data.psiData || [];
          gearData = data.gearData || [];
          gforceData = data.gforceData || [];
          currentX = data.currentX || 135; // Default to 135 if no saved position
        }
      }

      let svgDocument, rpmLine, wpLine, asLine, tpsLine, psiLine, gearLine, gforceLine;
      let rpmReadout, wheelSpeedReadout, airSpeedReadout, tpsReadout, psiReadout, gearReadout, gforceReadout;
      let movableLineElement, linePositionElement;
      let currentX = 135;
      const minX = 130;
      const maxX = 590;
      let rpmData = [], wpData = [], asData = [], tpsData = [], psiData = [], gearData = [], gforceData = [];
      let isRecording = false;  // Track recording state
      let isPlaying = false;
      let playInterval = null;
      let currentRPM = 0, currentWheelSpeed = 0, currentAirSpeed = 0, currentTPS = 0, currentPSI = 0, currentGear = 0, currentGForce = 0;
      let maxRPM = 16000;
      const secondsPerUnit = (maxX - minX) / 20;

      // Initialize Drag Pass Timers
scope.initializeDragPassTimers = function() {
    scope.start_time = null;  // Timestamp when the car leaves the start line

    // Timestamps for each distance marker
    scope.timestamp_60ft = null;
    scope.timestamp_330ft = null;
    scope.timestamp_660ft = null;  // 1/8 mile
    scope.timestamp_1000ft = null;
    scope.timestamp_1320ft = null; // 1/4 mile

    scope.distance_60ft = 0;
    scope.distance_330ft = 0;
    scope.distance_660ft = 0;
    scope.distance_1000ft = 0;
    scope.distance_1320ft = 0;
};

scope.updateDragPassTimers = function(streams) {
    if (!isRecording) {
        return;  // Exit early if not recording
    }

    const speedMs = streams.electrics.airspeed;
    const stopThreshold = 0.1;  // Small threshold to treat the car as stopped

    // Get the current logger runtime
    const currentTime = ((performance.now() - scope.loggerStartTime) / 1000).toFixed(2);  // Limit time to 2 decimal places

    const deltaTime = (currentTime - scope.lastUpdateTime).toFixed(2);  // Time in seconds since last update, 2 decimal places
    scope.lastUpdateTime = currentTime;

    const distanceTraveled = speedMs * deltaTime;

    // Check if the car has left the starting line (speed > threshold)
    if (!scope.start_time && speedMs >= stopThreshold) {
        scope.start_time = currentTime;
        console.log("Car started at:", scope.start_time, "seconds");
    }

    // Track 60ft
    if (!scope.timestamp_60ft && scope.start_time && speedMs >= stopThreshold) {
        scope.distance_60ft += distanceTraveled;
        if (scope.distance_60ft >= scope.goalEnd_60ft) {
            scope.timestamp_60ft = currentTime;
            console.log("60ft reached at:", scope.timestamp_60ft, "seconds");
        }
    }

    // Track 330ft
    if (!scope.timestamp_330ft && scope.start_time && speedMs >= stopThreshold) {
        scope.distance_330ft += distanceTraveled;
        if (scope.distance_330ft >= scope.goalEnd_330ft) {
            scope.timestamp_330ft = currentTime;
            console.log("330ft reached at:", scope.timestamp_330ft, "seconds");
        }
    }

    // Track 660ft (1/8th mile)
    if (!scope.timestamp_660ft && scope.start_time && speedMs >= stopThreshold) {
        scope.distance_660ft += distanceTraveled;
        if (scope.distance_660ft >= scope.goalEnd_660ft) {
            scope.timestamp_660ft = currentTime;
            console.log("660ft (1/8 mile) reached at:", scope.timestamp_660ft, "seconds");
        }
    }

    // Track 1000ft
    if (!scope.timestamp_1000ft && scope.start_time && speedMs >= stopThreshold) {
        scope.distance_1000ft += distanceTraveled;
        if (scope.distance_1000ft >= scope.goalEnd_1000ft) {
            scope.timestamp_1000ft = currentTime;
            console.log("1000ft reached at:", scope.timestamp_1000ft, "seconds");
        }
    }

    // Track 1320ft (1/4 mile)
    if (!scope.timestamp_1320ft && scope.start_time && speedMs >= stopThreshold) {
        scope.distance_1320ft += distanceTraveled;
        if (scope.distance_1320ft >= scope.goalEnd_1320ft) {
            scope.timestamp_1320ft = currentTime;
            console.log("1320ft (1/4 mile) reached at:", scope.timestamp_1320ft, "seconds");
        }
    }

    // Reset distances if the car stops
    if (speedMs < stopThreshold) {
        scope.initializeDragPassTimers();  // Reset timers when the car stops
    }
};


element.on('load', function() {
    svgDocument = element[0].contentDocument;
    rpmLine = svgDocument.getElementById('rpmLine');
    wpLine = svgDocument.getElementById('wpLine');
    asLine = svgDocument.getElementById('asLine');
    tpsLine = svgDocument.getElementById('tpsLine');
    psiLine = svgDocument.getElementById('psiLine');
    gearLine = svgDocument.getElementById('gearLine');
    gforceLine = svgDocument.getElementById('gforceLine');

    rpmReadout = svgDocument.getElementById('rpmReadout');
    wheelSpeedReadout = svgDocument.getElementById('wheelSpeed');
    airSpeedReadout = svgDocument.getElementById('airSpeed');
    tpsReadout = svgDocument.getElementById('tpsReadout');
    psiReadout = svgDocument.getElementById('psiReadout');
    gearReadout = svgDocument.getElementById('gearReadout');
    gforceReadout = svgDocument.getElementById('gforceReadout');

    movableLineElement = svgDocument.getElementById('movableLine');
    linePositionElement = svgDocument.getElementById('linePosition');

    const startButton = svgDocument.getElementById('startButton');
    const button60ft = svgDocument.getElementById('60ftButton');
    const button330ft = svgDocument.getElementById('330ftButton');
    const button660ft = svgDocument.getElementById('660ftButton');
    const button1000ft = svgDocument.getElementById('1000ftButton');
    const button1320ft = svgDocument.getElementById('1320ftButton');

    const leftArrowInner = svgDocument.getElementById('leftArrowInner');
    const rightArrowInner = svgDocument.getElementById('rightArrowInner');
    const leftArrowOuter = svgDocument.getElementById('leftArrowOuter');
    const rightArrowOuter = svgDocument.getElementById('rightArrowOuter');
    const playPauseButton = svgDocument.getElementById('playPauseButton');
    const playSymbol = svgDocument.getElementById('playSymbol');
    const pauseSymbol = svgDocument.getElementById('pauseSymbol');

    const Record = svgDocument.getElementById('Record');
    const RecordRect = Record.querySelector('rect');
    const RecordText = Record.querySelector('text');

    let rpmCheckbox = svgDocument.getElementById('rpmCheckbox');
    let wpCheckbox = svgDocument.getElementById('wpCheckbox');
    let asCheckbox = svgDocument.getElementById('asCheckbox');
    let tpsCheckbox = svgDocument.getElementById('tpsCheckbox');
    let psiCheckbox = svgDocument.getElementById('psiCheckbox');
    let gearCheckbox = svgDocument.getElementById('gearCheckbox');
    let gforceCheckbox = svgDocument.getElementById('gforceCheckbox');

    function toggleCheckbox(checkbox, line) {
        let isChecked = checkbox.getAttribute('fill') === 'green';
        checkbox.setAttribute('fill', isChecked ? 'red' : 'green');
        line.style.display = isChecked ? 'none' : 'inline';
    }

    rpmCheckbox.addEventListener('click', function() {
        toggleCheckbox(rpmCheckbox, rpmLine);
    });

    wpCheckbox.addEventListener('click', function() {
        toggleCheckbox(wpCheckbox, wpLine);
    });

    asCheckbox.addEventListener('click', function() {
        toggleCheckbox(asCheckbox, asLine);
    });

    tpsCheckbox.addEventListener('click', function() {
        toggleCheckbox(tpsCheckbox, tpsLine);
    });

    psiCheckbox.addEventListener('click', function() {
        toggleCheckbox(psiCheckbox, psiLine);
    });

    gearCheckbox.addEventListener('click', function() {
        toggleCheckbox(gearCheckbox, gearLine);
    });

    gforceCheckbox.addEventListener('click', function() {
        toggleCheckbox(gforceCheckbox, gforceLine);
    });

    // Update Readouts
    function updateRPMReadout(timeInSeconds) {
        const closestDataPoint = rpmData.reduce((prev, curr) => {
            return (Math.abs(curr.time - timeInSeconds) < Math.abs(prev.time - timeInSeconds) ? curr : prev);
        }, rpmData[0]);

        if (closestDataPoint) {
            rpmReadout.textContent = ' ' + closestDataPoint.rpm.toFixed(2);
        }
    }

    function updateWheelSpeedReadout(timeInSeconds) {
        const closestWPData = wpData.reduce((prev, curr) => {
            return (Math.abs(curr.time - timeInSeconds) < Math.abs(prev.time - timeInSeconds) ? curr : prev);
        }, wpData[0]);

        if (closestWPData) {
            wheelSpeedReadout.textContent = ' ' + (closestWPData.wheelSpeed * 2.23694).toFixed(2) + ' mph';
        }
    }

    function updateAirSpeedReadout(timeInSeconds) {
        const closestASData = asData.reduce((prev, curr) => {
            return (Math.abs(curr.time - timeInSeconds) < Math.abs(prev.time - timeInSeconds) ? curr : prev);
        }, asData[0]);

        if (closestASData) {
            airSpeedReadout.textContent = ' ' + (closestASData.airSpeed * 2.23694).toFixed(2) + ' mph';
        }
    }

    function updateTPSReadout(timeInSeconds) {
        const closestTPSData = tpsData.reduce((prev, curr) => {
            return (Math.abs(curr.time - timeInSeconds) < Math.abs(prev.time - timeInSeconds) ? curr : prev);
        }, tpsData[0]);

        if (closestTPSData) {
            tpsReadout.textContent = ' ' + (closestTPSData.tps * 100).toFixed(2) + ' %';
        }
    }

    function updatePSIReadout(timeInSeconds) {
        const closestPSIData = psiData.reduce((prev, curr) => {
            return (Math.abs(curr.time - timeInSeconds) < Math.abs(prev.time - timeInSeconds) ? curr : prev);
        }, psiData[0]);

        if (closestPSIData) {
            psiReadout.textContent = ' ' + closestPSIData.psi.toFixed(2) + ' psi';
        }
    }

    function updateGearReadout(timeInSeconds) {
        const closestGearData = gearData.reduce((prev, curr) => {
            return (Math.abs(curr.time - timeInSeconds) < Math.abs(prev.time - timeInSeconds) ? curr : prev);
        }, gearData[0]);

        if (closestGearData) {
            gearReadout.textContent = ' ' + closestGearData.gear;
        }
    }

    function updateGForceReadout(timeInSeconds) {
        const closestGForceData = gforceData.reduce((prev, curr) => {
            return (Math.abs(curr.time - timeInSeconds) < Math.abs(prev.time - timeInSeconds) ? curr : prev);
        }, gforceData[0]);

        if (closestGForceData) {
            gforceReadout.textContent = ' ' + closestGForceData.gforce.toFixed(2);
        }
    }

    // Function to move the line to a specific timestamp
    function moveVerticalLineToTime(timeInSeconds) {
        const position = minX + (timeInSeconds / 20) * (maxX - minX);
        currentX = position;
        updateLinePosition();
    }

    // Add event listeners to buttons for specific time points
    startButton.addEventListener('click', function() {
        moveVerticalLineToTime(scope.start_time || 0);  // Default to 0 if no start time is set
    });

    button60ft.addEventListener('click', function() {
        moveVerticalLineToTime(scope.timestamp_60ft || 0);
    });

    button330ft.addEventListener('click', function() {
        moveVerticalLineToTime(scope.timestamp_330ft || 0);
    });

    button660ft.addEventListener('click', function() {
        moveVerticalLineToTime(scope.timestamp_660ft || 0);
    });

    button1000ft.addEventListener('click', function() {
        moveVerticalLineToTime(scope.timestamp_1000ft || 0);
    });

    button1320ft.addEventListener('click', function() {
        moveVerticalLineToTime(scope.timestamp_1320ft || 0);
    });

    function updateGraph() {
        let rpmPoints = rpmData.map(data => {
            let x = 130 + (data.time / 20) * (590 - 128);
            let y = 263 - (data.rpm / maxRPM) * (263 - 110);
            return `${x},${y}`;
        }).filter(point => point !== '').join(' ');
        rpmLine.setAttribute('points', rpmPoints);

        let wpPoints = wpData.map(data => {
            let x = 130 + (data.time / 20) * (590 - 128);
            let y = 263 - (data.wheelSpeed * 2.23694 / 400) * (263 - 50);
            return `${x},${y}`;
        }).filter(point => point !== '').join(' ');
        wpLine.setAttribute('points', wpPoints);

        let asPoints = asData.map(data => {
            let x = 130 + (data.time / 20) * (590 - 128);
            let y = 263 - (data.airSpeed * 2.23694 / 400) * (263 - 50);
            if (isNaN(x) || isNaN(y)) return '';
            return `${x},${y}`;
        }).filter(point => point !== '').join(' ');
        asLine.setAttribute('points', asPoints);

        let tpsPoints = tpsData.map(data => {
            let x = 130 + (data.time / 20) * (590 - 128);
            let y = 263 - ((data.tps * 100) / 100) * (263 - 90);
            if (isNaN(x) || isNaN(y)) return '';
            return `${x},${y}`;
        }).filter(point => point !== '').join(' ');
        tpsLine.setAttribute('points', tpsPoints);

        let psiPoints = psiData.map(data => {
            let x = 130 + (data.time / 20) * (590 - 128);
            let y = 263 - ((data.psi + 14.7) / (150 + 14.7)) * (263 - 50);
            if (isNaN(x) || isNaN(y)) return '';
            return `${x},${y}`;
        }).filter(point => point !== '').join(' ');
        psiLine.setAttribute('points', psiPoints);

        let gearPoints = gearData.map(data => {
            let x = 130 + (data.time / 20) * (590 - 128);
            let y = 263 - ((data.gear + 1) / 11) * (263 - 50);
            if (isNaN(x) || isNaN(y)) return '';
            return `${x},${y}`;
        }).filter(point => point !== '').join(' ');
        gearLine.setAttribute('points', gearPoints);

        let gforcePoints = gforceData.map(data => {
            let x = 130 + (data.time / 20) * (590 - 128);
            let y = 263 - ((data.gforce + 3) / 15) * (263 - 50);
            if (isNaN(x) || isNaN(y)) return '';
            return `${x},${y}`;
        }).filter(point => point !== '').join(' ');
        gforceLine.setAttribute('points', gforcePoints);
    }

    function updatePositionDisplay() {
        const seconds = ((currentX - minX) / secondsPerUnit).toFixed(2);
        linePositionElement.textContent = seconds + 's';
        updateRPMReadout(seconds);
        updateWheelSpeedReadout(seconds);
        updateAirSpeedReadout(seconds);
        updateTPSReadout(seconds);
        updatePSIReadout(seconds);
        updateGearReadout(seconds);
        updateGForceReadout(seconds);
    }

    function updateLinePosition() {
        movableLineElement.setAttribute('x1', currentX);
        movableLineElement.setAttribute('x2', currentX);
        updatePositionDisplay();
    }

        // Start recording function that initializes the logger's start time
        function startRecording() {
      isRecording = true;

      // Initialize logger start time
      scope.loggerStartTime = performance.now();  // Capture the exact time the logger starts
      console.log("Logger start time initialized (in ms):", scope.loggerStartTime);

      // Convert the logger start time to seconds and limit it to two decimal places
      let loggerStartSeconds = (scope.loggerStartTime / 1000).toFixed(2);
      console.log("Logger started at (in seconds):", loggerStartSeconds, "seconds");

      // Initialize timers and recording
      scope.initializeDragPassTimers();
      currentX = minX;  // Move the line to the beginning
      updateLinePosition();  // Update the line position to the start

      rpmData = [], wpData = [], asData = [], tpsData = [], psiData = [], gearData = [], gforceData = [];

      let interval = setInterval(function() {
          const now = performance.now();  // Get the current time
          const currentTime = ((now - scope.loggerStartTime) / 1000).toFixed(2);  // Time in seconds since recording started, limited to 2 decimal places

          if (currentTime >= 20 || !isRecording) {  // Stop recording when time reaches or user clicks stop
              clearInterval(interval);
              isRecording = false;

              // Move the line back to the center when done recording
              currentX = (minX + maxX) / 2;
              updateLinePosition();

              // Change button back to green Start
              RecordRect.setAttribute('fill', '#00FF00');
              RecordText.textContent = 'Record';
              return;
          }

          // Update the line position as time progresses
          currentX = minX + (currentTime / 20) * (maxX - minX);  // Move the line with time
          updateLinePosition();

          // Push data for graph updates, limit time values to two decimal places
          rpmData.push({ time: currentTime, rpm: currentRPM });
          wpData.push({ time: currentTime, wheelSpeed: currentWheelSpeed });
          asData.push({ time: currentTime, airSpeed: currentAirSpeed });
          tpsData.push({ time: currentTime, tps: currentTPS });
          psiData.push({ time: currentTime, psi: currentPSI });
          gearData.push({ time: currentTime, gear: currentGear });
          gforceData.push({ time: currentTime, gforce: currentGForce });

          updateGraph();  // Update the graph visualization
      }, 10);
  }

  // Toggle Start/Stop button functionality
  Record.addEventListener('click', function() {
      if (!isRecording) {
          // Start recording
          startRecording();

          // Change button to red Stop
          RecordRect.setAttribute('fill', 'red');
          RecordText.textContent = 'Stop';
      } else {
          // Stop recording
          isRecording = false;  // Stop the recording

          // Change button back to green Start
          RecordRect.setAttribute('fill', '#00FF00');
          RecordText.textContent = 'Record';
      }
  });

        function togglePlayPause() {
          if (isPlaying) {
            // Pause the playback
            clearInterval(playInterval);
            isPlaying = false;
            playSymbol.style.display = 'inline';  // Show the play triangle
            pauseSymbol.style.display = 'none';   // Hide the pause bars
          } else {
            // Start playing
            playInterval = setInterval(function() {
              if (currentX < maxX) {
                currentX += (secondsPerUnit / 100); // Adjust for playback speed
                if (currentX > maxX) {
                  currentX = maxX;
                  clearInterval(playInterval);
                }
                updateLinePosition();
              } else {
                clearInterval(playInterval);  // Stop playback at the end
              }
            }, 10); // Adjust this for speed control (10ms = smooth real-time)
            isPlaying = true;
            playSymbol.style.display = 'none';   // Hide the play triangle
            pauseSymbol.style.display = 'inline'; // Show the pause bars
          }
        }

        playPauseButton.addEventListener('click', function() {
          togglePlayPause();  // Toggle play or pause when the button is clicked
        });

        // Event listeners for the inner and outer arrows
        leftArrowInner.addEventListener('mousedown', function(event) {
          if (event.button === 0) {  // Left click
            if (currentX > minX) {
              currentX -= secondsPerUnit;
              if (currentX < minX) currentX = minX;  // Bound check
              updateLinePosition();
            }
          } else if (event.button === 2) {  // Right click
            if (currentX > minX) {
              currentX -= secondsPerUnit / 2;
              if (currentX < minX) currentX = minX;
              updateLinePosition();
            }
          }
        });

        rightArrowInner.addEventListener('mousedown', function(event) {
          if (event.button === 0) {  // Left click
            if (currentX < maxX) {
              currentX += secondsPerUnit;
              if (currentX > maxX) currentX = maxX;  // Bound check
              updateLinePosition();
            }
          } else if (event.button === 2) {  // Right click
            if (currentX < maxX) {
              currentX += secondsPerUnit / 2;
              if (currentX > maxX) currentX = maxX;
              updateLinePosition();
            }
          }
        });

        leftArrowOuter.addEventListener('mousedown', function(event) {
          if (event.button === 0) {  // Left click
            if (currentX > minX) {
              currentX -= (secondsPerUnit / 10);
              if (currentX < minX) currentX = minX;
              updateLinePosition();
            }
          } else if (event.button === 2) {  // Right click
            if (currentX > minX) {
              currentX -= (secondsPerUnit / 100);
              if (currentX < minX) currentX = minX;
              updateLinePosition();
            }
          }
        });

        rightArrowOuter.addEventListener('mousedown', function(event) {
          if (event.button === 0) {  // Left click
            if (currentX < maxX) {
              currentX += (secondsPerUnit / 10);
              if (currentX > maxX) currentX = maxX;
              updateLinePosition();
            }
          } else if (event.button === 2) {  // Right click
            if (currentX < maxX) {
              currentX += (secondsPerUnit / 100);
              if (currentX > maxX) currentX = maxX;
              updateLinePosition();
            }
          }
        });

        svgDocument.addEventListener('contextmenu', function(event) {
          event.preventDefault();
        });

        scope.$on('streamsUpdate', function(event, streams) {
          if (streams.engineInfo && streams.engineInfo.length > 4) {
            currentRPM = streams.engineInfo[4];
            currentWheelSpeed = streams.electrics.wheelspeed;
            currentAirSpeed = streams.electrics.airspeed;
            currentTPS = streams.electrics.throttle;
            currentPSI = streams.electrics.boost;
            currentGear = streams.electrics.gear;

            if (streams.engineInfo.length > 1) {
              maxRPM = streams.engineInfo[1] || 16000;
            }

            const gravity = streams.sensors.gravity || 9.81;
            const gx2 = streams.sensors.gx2 || 0;
            const gy2 = streams.sensors.gy2 || 0;
            const gz2 = streams.sensors.gz2 || 0;

            currentGForce = Math.sqrt(gx2 * gx2 + gy2 * gy2 + (gz2 + 9.81) * (gz2 + 9.81)) / 9.81;
          }

          // Update drag pass timers with the stream data
          scope.updateDragPassTimers(streams);
        });

        scope.$on('$destroy', function() {
          saveData();
          rpmLine = null;
          wpLine = null;
          asLine = null;
          tpsLine = null;
          psiLine = null;
          gearLine = null;
          gforceLine = null;
          rpmReadout = null;
          wheelSpeedReadout = null;
          airSpeedReadout = null;
          tpsReadout = null;
          psiReadout = null;
          gearReadout = null;
          gforceReadout = null;
          movableLineElement = null;
          linePositionElement = null;
        });

        loadData();
        updateLinePosition(); // Restore the vertical line position on load
        updateGraph(); // Restore the graph data on load
        scope.initializeDragPassTimers(); // Initialize drag pass timers on load
      });
    }
  };
}]);
