#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
#include <IRremote.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET     -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define FAN_PIN 9
#define ZC_PIN 2
#define BUTTON_INC_PIN 3
#define BUTTON_DEC_PIN 4
#define BUTTON_LIGHT1_PIN 10
#define BUTTON_LIGHT2_PIN 11
#define BUTTON_LIGHT3_PIN 12
#define IR_PIN 8

#define LIGHT1_PIN 5
#define LIGHT2_PIN 6
#define LIGHT3_PIN 7

#define EEPROM_FAN_SPEED_ADDR 0
#define EEPROM_LIGHT1_STATE_ADDR 1
#define EEPROM_LIGHT2_STATE_ADDR 2
#define EEPROM_LIGHT3_STATE_ADDR 3

int fanSpeed = 0;
const int maxSpeed = 255;
const int minSpeed = 0;
volatile bool zeroCrossed = false;
bool light1State = false;
bool light2State = false;
bool light3State = false;

IRrecv irrecv(IR_PIN);
decode_results results;

const unsigned long IR_CODE_FAN_INC = 0xFF629D;  // Replace with your IR remote code
const unsigned long IR_CODE_FAN_DEC = 0xFFA857;  // Replace with your IR remote code
const unsigned long IR_CODE_LIGHT1_TOGGLE = 0xFF22DD;  // Replace with your IR remote code
const unsigned long IR_CODE_LIGHT2_TOGGLE = 0xFF02FD;  // Replace with your IR remote code
const unsigned long IR_CODE_LIGHT3_TOGGLE = 0xFFC23D;  // Replace with your IR remote code

void setup() {
  pinMode(FAN_PIN, OUTPUT);
  pinMode(ZC_PIN, INPUT);
  pinMode(BUTTON_INC_PIN, INPUT);
  pinMode(BUTTON_DEC_PIN, INPUT);
  pinMode(BUTTON_LIGHT1_PIN, INPUT);
  pinMode(BUTTON_LIGHT2_PIN, INPUT);
  pinMode(BUTTON_LIGHT3_PIN, INPUT);
  pinMode(LIGHT1_PIN, OUTPUT);
  pinMode(LIGHT2_PIN, OUTPUT);
  pinMode(LIGHT3_PIN, OUTPUT);

  digitalWrite(BUTTON_INC_PIN, LOW);
  digitalWrite(BUTTON_DEC_PIN, LOW);
  digitalWrite(BUTTON_LIGHT1_PIN, LOW);
  digitalWrite(BUTTON_LIGHT2_PIN, LOW);
  digitalWrite(BUTTON_LIGHT3_PIN, LOW);

  attachInterrupt(digitalPinToInterrupt(ZC_PIN), zeroCrossISR, RISING);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.print("Fan & Light Control");
  display.display();

  // Retrieve stored values from EEPROM
  fanSpeed = EEPROM.read(EEPROM_FAN_SPEED_ADDR);
  light1State = EEPROM.read(EEPROM_LIGHT1_STATE_ADDR);
  light2State = EEPROM.read(EEPROM_LIGHT2_STATE_ADDR);
  light3State = EEPROM.read(EEPROM_LIGHT3_STATE_ADDR);

  // Initialize lights and fan to stored states
  analogWrite(FAN_PIN, fanSpeed);
  digitalWrite(LIGHT1_PIN, light1State ? HIGH : LOW);
  digitalWrite(LIGHT2_PIN, light2State ? HIGH : LOW);
  digitalWrite(LIGHT3_PIN, light3State ? HIGH : LOW);

  irrecv.enableIRIn(); // Start the IR receiver
}

void loop() {
  static int lastFanSpeed = fanSpeed;
  static bool lastLight1State = light1State;
  static bool lastLight2State = light2State;
  static bool lastLight3State = light3State;

  if (digitalRead(BUTTON_INC_PIN) == HIGH) {
    fanSpeed = constrain(fanSpeed + 5, minSpeed, maxSpeed);
    delay(200); // Debounce delay
  }
  if (digitalRead(BUTTON_DEC_PIN) == HIGH) {
    fanSpeed = constrain(fanSpeed - 5, minSpeed, maxSpeed);
    delay(200); // Debounce delay
  }

  if (zeroCrossed) {
    analogWrite(FAN_PIN, fanSpeed);
    zeroCrossed = false;
  }

  if (digitalRead(BUTTON_LIGHT1_PIN) == HIGH) {
    light1State = !light1State;
    digitalWrite(LIGHT1_PIN, light1State ? HIGH : LOW);
    delay(200); // Debounce delay
  }
  if (digitalRead(BUTTON_LIGHT2_PIN) == HIGH) {
    light2State = !light2State;
    digitalWrite(LIGHT2_PIN, light2State ? HIGH : LOW);
    delay(200); // Debounce delay
  }
  if (digitalRead(BUTTON_LIGHT3_PIN) == HIGH) {
    light3State = !light3State;
    digitalWrite(LIGHT3_PIN, light3State ? HIGH : LOW);
    delay(200); // Debounce delay
  }

  // Check for IR signals
  if (irrecv.decode(&results)) {
    unsigned long irCode = results.value;
    irrecv.resume(); // Receive the next value

    if (irCode == IR_CODE_FAN_INC) {
      fanSpeed = constrain(fanSpeed + 5, minSpeed, maxSpeed);
    } else if (irCode == IR_CODE_FAN_DEC) {
      fanSpeed = constrain(fanSpeed - 5, minSpeed, maxSpeed);
    } else if (irCode == IR_CODE_LIGHT1_TOGGLE) {
      light1State = !light1State;
      digitalWrite(LIGHT1_PIN, light1State ? HIGH : LOW);
    } else if (irCode == IR_CODE_LIGHT2_TOGGLE) {
      light2State = !light2State;
      digitalWrite(LIGHT2_PIN, light2State ? HIGH : LOW);
    } else if (irCode == IR_CODE_LIGHT3_TOGGLE) {
      light3State = !light3State;
      digitalWrite(LIGHT3_PIN, light3State ? HIGH : LOW);
    }
  }

  // Save changes to EEPROM
  if (fanSpeed != lastFanSpeed) {
    EEPROM.write(EEPROM_FAN_SPEED_ADDR, fanSpeed);
    lastFanSpeed = fanSpeed;
  }
  if (light1State != lastLight1State) {
    EEPROM.write(EEPROM_LIGHT1_STATE_ADDR, light1State);
    lastLight1State = light1State;
  }
  if (light2State != lastLight2State) {
    EEPROM.write(EEPROM_LIGHT2_STATE_ADDR, light2State);
    lastLight2State = light2State;
  }
  if (light3State != lastLight3State) {
    EEPROM.write(EEPROM_LIGHT3_STATE_ADDR, light3State);
    lastLight3State = light3State;
  }

  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("Fan & Light Control");
  display.setCursor(0, 20);
  display.print("Fan Speed: ");
  display.print(fanSpeed);
  display.setCursor(0, 40);
  display.print("Light 1: ");
  display.print(light1State ? "On" : "Off");
  display.setCursor(0, 50);
  display.print("Light 2: ");
  display.print(light2State ? "On" : "Off");
  display.setCursor(0, 60);
  display.print("Light 3: ");
  display.print(light3State ? "On" : "Off");
  display.display();

  delay(100);
}

void zeroCrossISR() {
  zeroCrossed = true;
}