#include <Arduino.h>
#include <EEPROM.h>
#include <MD_Parola.h>
#include <MD_MAX72XX.h>
#include <SPI.h>

// Matrix Display Configuration
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define DATA_PIN 11
#define CLK_PIN  13
#define CS_PIN   10
#define MAX_DEVICES 8

MD_Parola display = MD_Parola(
  HARDWARE_TYPE,
  DATA_PIN,
  CLK_PIN,
  CS_PIN,
  MAX_DEVICES
);

// Coin Acceptor Configuration
volatile byte impulsCount = 0;
volatile unsigned long lastPulseTime = 0;
unsigned long total_amount = 0;
#define COIN_TIMEOUT 400   // ms

// Display States
enum DisplayState {
  STATE_WELCOME,
  STATE_COIN_INSERTED,
  STATE_SHOW_LITERS,
  STATE_REPEAT_AMOUNT
};

DisplayState currentState = STATE_WELCOME;
unsigned long stateStartTime = 0;
unsigned long coinInsertTime = 0;
unsigned long lastAmount = 0;
bool animationFinished = false;
char displayText[50] = "";

void setup() {
  Serial.begin(9600);

  // Coin acceptor setup
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), incomingImpuls, FALLING);

  // EEPROM setup
  EEPROM.get(0, total_amount);
  if (total_amount > 10000000UL) {
    total_amount = 0;
    EEPROM.put(0, total_amount);
  }

  // Display setup
  display.begin();
  display.setIntensity(5);
  display.displayClear();

  // Start with welcome message
  showWelcomeMessage();

  Serial.println("Coin acceptor ready. Insert coin...");
}

void incomingImpuls() {
  impulsCount++;
  lastPulseTime = millis();
}

void showWelcomeMessage() {
  currentState = STATE_WELCOME;
  stateStartTime = millis();
  display.displayClear();
  display.displayScroll(
    "karibu upate maji lita 20L kwa 100TZS",
    PA_CENTER,
    PA_SCROLL_LEFT,
    80
  );
}

void showCoinInserted(unsigned long amount) {
  currentState = STATE_COIN_INSERTED;
  stateStartTime = millis();
  coinInsertTime = millis();
  lastAmount = amount;
  animationFinished = false;
  
  display.displayClear();
  sprintf(displayText, "umeweka %lu TZS", amount);
  display.displayScroll(
    displayText,
    PA_CENTER,
    PA_SCROLL_LEFT,
    80
  );
  
  Serial.print("umeweka ");
  Serial.print(amount);
  Serial.println(" TZS");
}

void showLiters(unsigned long amount) {
  currentState = STATE_SHOW_LITERS;
  stateStartTime = millis();
  
  // Calculate liters: 100 TZS = 20L, 200 TZS = 40L
  unsigned long liters = (amount / 100) * 20;
  
  display.displayClear();
  sprintf(displayText, "PATA %lu L", liters);
  display.displayText(
    displayText,
    PA_CENTER,
    0,
    0,
    PA_NO_EFFECT,
    PA_NO_EFFECT
  );
  display.displayReset();  // Ensure display is active
  
  Serial.print("PATA ");
  Serial.print(liters);
  Serial.println(" L");
}

void showRepeatAmount(unsigned long amount) {
  currentState = STATE_REPEAT_AMOUNT;
  stateStartTime = millis();
  animationFinished = false;
  
  display.displayClear();
  sprintf(displayText, "umeweka %lu TZS", amount);
  display.displayScroll(
    displayText,
    PA_CENTER,
    PA_SCROLL_LEFT,
    80
  );
}

void loop() {
  // Handle coin detection
  if (impulsCount > 0 && (millis() - lastPulseTime) > COIN_TIMEOUT) {
    unsigned long coinValue = 0;
    
    if (impulsCount == 1) {
      coinValue = 100;
      total_amount += 100;
      Serial.println("100 TZS accepted");
    }
    else if (impulsCount == 2) {
      coinValue = 200;
      total_amount += 200;
      Serial.println("200 TZS accepted");
    }
    else {
      Serial.print("Invalid coin pulses: ");
      Serial.println(impulsCount);
      impulsCount = 0;
      return;
    }

    EEPROM.put(0, total_amount);
    Serial.print("TOTAL = ");
    Serial.print(total_amount);
    Serial.println(" TZS");

    impulsCount = 0;
    
    // Show coin inserted message
    showCoinInserted(coinValue);
  }

  // Handle display states
  unsigned long currentTime = millis();
  
  switch (currentState) {
    case STATE_WELCOME:
      // Animate welcome message (keep looping)
      if (display.displayAnimate()) {
        display.displayReset();  // Loop the animation
      }
      break;
      
    case STATE_COIN_INSERTED:
      // Animate coin inserted message, wait for it to finish
      if (display.displayAnimate()) {
        if (!animationFinished) {
          animationFinished = true;
          // Animation finished, now show liters
          showLiters(lastAmount);
        }
      }
      break;
      
    case STATE_SHOW_LITERS:
      // Keep refreshing the static display
      display.displayAnimate();
      
      // Show liters centered for 20 seconds (20000 ms)
      if (currentTime - stateStartTime >= 20000) {
        // Check if 3 minutes have passed since coin insertion
        if (currentTime - coinInsertTime >= 180000) {  // 3 minutes = 180000 ms
          showWelcomeMessage();
        } else {
          showRepeatAmount(lastAmount);
        }
      }
      break;
      
    case STATE_REPEAT_AMOUNT:
      // Animate repeat amount message, wait for it to finish
      if (display.displayAnimate()) {
        if (!animationFinished) {
          animationFinished = true;
          // Animation finished, check if 3 minutes have passed
          if (currentTime - coinInsertTime >= 180000) {  // 3 minutes = 180000 ms
            showWelcomeMessage();
          } else {
            // Go back to liters (alternating)
            showLiters(lastAmount);
          }
        }
      }
      break;
  }
}
FC 
