#include <Arduino.h>
#include <Adafruit_SSD1306.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
#include "config.h"
#include "SmartCube/cubeSound.h"
#include "SmartCube/cubeButtons.h"
#include "SmartCube/cubeWifiManager.h"

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
cubeWifiManager cubeWifiManager(display);

unsigned long lastRefresh = 0;
const unsigned long refreshInterval = 60000; // 60 seconds

String lastEventId = "";
String problems[10];
String problemDescriptions;
int problemCount = 0;
int severityCounts[6] = {0};
bool newProblemsDetected = false;
int totalProblems = 0; // Variable to store the total number of active problems

// History buffer for the graph
const int maxHistorySize = 30;
int problemHistory[maxHistorySize] = {0};  // Array to store history
int historyIndex = 0;                      // Current index for the latest value

int scrollPos = SCREEN_WIDTH;         // Global variable to keep track of the scroll position
unsigned long lastScrollTime = 0;     // To control the scroll speed
const int scrollDelay = 120;          // Delay in milliseconds between scroll updates

void initSystems() {
  pinMode(PIN_BTN_L, INPUT);
  pinMode(PIN_BTN_M, INPUT);
  pinMode(PIN_BTN_R, INPUT);
  pinMode(PIN_BUZZER, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  Wire.begin();             // Initialize I2C
  Wire.setClock(400000L);    // Set I2C to Fast Mode (400 kHz)
  display.ssd1306_command(SSD1306_SETCONTRAST);
  display.ssd1306_command(200);  // Value between 0 and 255

  // Initialize the SSD1306 display
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Adjust I2C address if needed
    for (;;); // Don't proceed, loop forever
  }

  // Rotate the display 180 degrees
  display.setRotation(2);

  // Clear the display buffer
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.display();
}

void fetchActiveProblems() {
  WiFiClient client;
  HTTPClient http;
  http.begin(client, zabbixServer);
  http.setTimeout(5000);  // 5-second timeout
  http.addHeader("Content-Type", "application/json");

  // JSON payload
  DynamicJsonDocument doc(2048); // Increased to avoid memory issues
  doc["jsonrpc"] = "2.0";
  doc["method"] = "problem.get";
  doc["id"] = 1;
  doc["auth"] = zabbixToken;
  JsonObject params = doc["params"].to<JsonObject>();
  params["output"] = "extend";
  params["recent"] = true;
  params["sortfield"] = "eventid";
  params["sortorder"] = "DESC";

  String requestBody;
  serializeJson(doc, requestBody);

  // POST request
  int httpResponseCode = http.POST(requestBody);

  if (httpResponseCode > 0) {
    String response = http.getString();

    // Parse response
    DynamicJsonDocument responseDoc(8192); // Increased size to fit more data
    DeserializationError error = deserializeJson(responseDoc, response);

    if (!error) {
      JsonArray result = responseDoc["result"].as<JsonArray>();

      // Clear descriptions and severity counts
      memset(severityCounts, 0, sizeof(severityCounts));
      problemDescriptions = ""; // Reset before appending

      totalProblems = result.size(); // Set total problems count

      // Store the current totalProblems in the history buffer
      problemHistory[historyIndex] = totalProblems;
      historyIndex = (historyIndex + 1) % maxHistorySize;  // Circular buffer

      int newProblemCount = 0;
      for (JsonObject problem : result) {
        String eventId = problem["eventid"].as<String>();
        int severity = problem["severity"].as<int>();
        String description = problem["name"].as<String>();

        // Check for new problems by comparing event IDs
        if (eventId.toInt() > lastEventId.toInt()) {
          newProblemsDetected = true;
        }

        if (severity >= 0 && severity < 5) {
          severityCounts[severity]++;
        }

        problemDescriptions += description + "      ";  // Append description with space for better display
        newProblemCount++;
      }

      problemCount = newProblemCount;

      if (problemCount > 0) {
        lastEventId = result[0]["eventid"].as<String>();
      }
    } else {
      beep(1000);
    }
  } else {
    problemDescriptions="Zabbix API error";
  }

  http.end();
}

void playAlertMelody() {
  int toneDuration = 60; // Each tone lasts 150ms
  int pauseDuration = 20; // Pause between tones

  // Play first tone
  tone(PIN_BUZZER, 1500);  // 1000 Hz
  delay(toneDuration);
  noTone(PIN_BUZZER);
  delay(pauseDuration);

  // Play second tone
  tone(PIN_BUZZER, 1200);  // 1200 Hz
  delay(toneDuration);
  noTone(PIN_BUZZER);
  delay(pauseDuration);

  // Play third tone
  tone(PIN_BUZZER, 1500);  // 1500 Hz
  delay(toneDuration);
  noTone(PIN_BUZZER);
}

void displayProblems() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.printf(" I:%d W:%d A:%d H:%d D:%d",
                 severityCounts[1],
                 severityCounts[2],
                 severityCounts[3],
                 severityCounts[4],
                 severityCounts[5]);
  display.drawLine(0, 45, 127, 45, 1);  // Line under the graph
  display.drawLine(0, 10, 127, 10, 1);  // Line under the graph

  // Draw the history graph
  int graphHeight = 30;   // Height of the graph
  int graphTop = 15;      // Top position of the graph
  int graphBottom = graphTop + graphHeight;

  int maxProblems = *std::max_element(problemHistory, problemHistory + maxHistorySize); // Find max for scaling
  if (maxProblems == 0) maxProblems = 1;  // Avoid division by zero

  for (int i = 0; i < maxHistorySize - 1; i++) {
    int x1 = (i * SCREEN_WIDTH) / maxHistorySize;
    int x2 = ((i + 1) * SCREEN_WIDTH) / maxHistorySize;

    int y1 = graphBottom - (problemHistory[(historyIndex + i) % maxHistorySize] * graphHeight) / maxProblems;
    int y2 = graphBottom - (problemHistory[(historyIndex + i + 1) % maxHistorySize] * graphHeight) / maxProblems;

    display.drawLine(x1, y1, x2, y2, 1);  // Draw line between points
  }

  // Scroll text below the graph
  int stateWidth = strlen(problemDescriptions.c_str()) * 12;

  if (!is_display_off) {
    if (millis() - lastScrollTime > scrollDelay) {
      scrollPos -= 11;
      lastScrollTime = millis();

      if (scrollPos < -stateWidth) {
        scrollPos = SCREEN_WIDTH;
      }
    }
  }

  display.setTextSize(2);
  display.setCursor(scrollPos, 48);
  display.print(problemDescriptions);
  display.setTextSize(1);
  display.fillRect(112,35,10,10,0);
  display.setCursor(113,36);
  display.print(totalProblems);
  display.display();
}

void setup() {
  initSystems();
  cubeWifiManager.start();
  fetchActiveProblems();
}

void loop() {
  unsigned long currentMillis = millis();
  cubeButtonHandler();

  if (!is_display_off && currentMillis - lastRefresh >= refreshInterval) {
    lastRefresh = currentMillis;
    fetchActiveProblems();
  }

  displayProblems();

  if (newProblemsDetected) {
    playAlertMelody();
    newProblemsDetected = false;
  }
}
