#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#include <avr/pgmspace.h>

// --- Objects ---
RTC_DS3231 rtc;
LiquidCrystal_I2C lcd(0x27, 16, 2);
Servo myServo;

// --- Pins ---
const int buttonTime = 2;
const int buttonIdea = 3;
const int buttonAge  = 4;
const int servoPin   = 5;

// --- Servo config ---
const int servoAngles[5] = {50, 70, 90, 120, 140};
unsigned long lastServoMove = 0;
unsigned long servoInterval = 30000; // initial 30s
int lastServoAngle = -1;            // track last angle written
unsigned long servoDetachTime = 0;
const unsigned long SERVO_HOLD_MS = 500; // ms to keep servo powered after move
bool servoIsAttached = false;
bool reportServoMoves = false;          // toggle serial reporting of servo moves

// --- Ideas storage ---
const int FIXED_IDEAS = 50;
String serialIdeas[50];
int serialIdeaCount = 0;
int currentIdeaIndex = 0;               // index into combined list (0..FIXED_IDEAS+serialIdeaCount-1)
bool deletedFlags[FIXED_IDEAS] = {false}; // track deleted built-in ideas

// --- Scrolling ---
int scrollOffset = 0;
unsigned long lastScroll = 0;
const unsigned long SCROLL_DELAY = 700; // ms between scroll steps

// --- UI state ---
enum Mode { SHOW_TIME, SHOW_AGE, SHOW_IDEA, CONFIRM_REMOVE };
Mode currentMode = SHOW_TIME;
String lastLine0 = "";
String lastLine1 = "";

// --- Button long-press tracking ---
unsigned long ideaButtonPressedAt = 0;
bool ideaButtonWasDown = false;
bool confirmYes = true; // default selection in confirm menu

// --- PROGMEM fixed ideas ---
const char idea0[] PROGMEM  = "Interactive shadow puppet theater ";
const char idea1[] PROGMEM  = "AI-assisted plant artist ";
const char idea2[] PROGMEM  = "Kinetic desktop sculpture ";
const char idea3[] PROGMEM  = "Musical watercolor machine ";
const char idea4[] PROGMEM  = "Solar-powered lantern array ";
const char idea5[] PROGMEM  = "Wearable mood-LED accessory ";
const char idea6[] PROGMEM  = "Autonomous bookshelf sorter ";
const char idea7[] PROGMEM  = "Voice-controlled cocktail maker ";
const char idea8[] PROGMEM  = "Paper-circuit greeting cards ";
const char idea9[] PROGMEM  = "Gesture-controlled drone lightshow ";
const char idea10[] PROGMEM = "Programmable countertop herb garden ";
const char idea11[] PROGMEM = "DIY smart window tint ";
const char idea12[] PROGMEM = "Retro handheld game console ";
const char idea13[] PROGMEM = "Pocket-sized weather station ";
const char idea14[] PROGMEM = "Mechanical music box remix ";
const char idea15[] PROGMEM = "Automated pet feeder with camera ";
const char idea16[] PROGMEM = "3D-printed mechanical puzzle ";
const char idea17[] PROGMEM = "Interactive constellation lamp ";
const char idea18[] PROGMEM = "Robotic bartender arm ";
const char idea19[] PROGMEM = "Theremin-style touch instrument ";
const char idea20[] PROGMEM = "Smart mirror with daily prompts ";
const char idea21[] PROGMEM = "Color-changing terrarium ";
const char idea22[] PROGMEM = "Magnetic levitation display ";
const char idea23[] PROGMEM = "Trash-to-art kinetic sculpture ";
const char idea24[] PROGMEM = "Gesture-controlled light painting ";
const char idea25[] PROGMEM = "Portable solar charger wallet ";
const char idea26[] PROGMEM = "Bioluminescent bottle lamp ";
const char idea27[] PROGMEM = "Arduino-powered mini pinball ";
const char idea28[] PROGMEM = "Wind-powered kinetic toy ";
const char idea29[] PROGMEM = "Voice-activated storybook ";
const char idea30[] PROGMEM = "Mini CNC-carved jewelry ";
const char idea31[] PROGMEM = "Heartbeat lamp (wearable sensor) ";
const char idea32[] PROGMEM = "Augmented reality scavenger hunt ";
const char idea33[] PROGMEM = "Holographic display with mirrors ";
const char idea34[] PROGMEM = "Retro flip-dot message board ";
const char idea35[] PROGMEM = "Hydroponic countertop garden ";
const char idea36[] PROGMEM = "Programmable paper automata ";
const char idea37[] PROGMEM = "Mini smart espresso tamper ";
const char idea38[] PROGMEM = "Glow-in-the-dark resin coasters ";
const char idea39[] PROGMEM = "Interactive sound-reactive rug ";
const char idea40[] PROGMEM = "Thermal camera mood wall ";
const char idea41[] PROGMEM = "Wearable air-quality badge ";
const char idea42[] PROGMEM = "Solar garden light orchestra ";
const char idea43[] PROGMEM = "DIY e-ink desk calendar ";
const char idea44[] PROGMEM = "Self-watering hanging planter ";
const char idea45[] PROGMEM = "Bluetooth knitting machine ";
const char idea46[] PROGMEM = "Laser-cut city skyline lamp ";
const char idea47[] PROGMEM = "Automated plant whisperer ";
const char idea48[] PROGMEM = "Pocket-sized laser harp ";
const char idea49[] PROGMEM = "Miniature mechanical orchestra";

const char* const ideaTable[] PROGMEM = {
  idea0, idea1, idea2, idea3, idea4, idea5, idea6, idea7, idea8, idea9,
  idea10, idea11, idea12, idea13, idea14, idea15, idea16, idea17, idea18, idea19,
  idea20, idea21, idea22, idea23, idea24, idea25, idea26, idea27, idea28, idea29,
  idea30, idea31, idea32, idea33, idea34, idea35, idea36, idea37, idea38, idea39,
  idea40, idea41, idea42, idea43, idea44, idea45, idea46, idea47, idea48, idea49
};

// --- Helpers ---
String getFixedIdea(int idx) {
    char buf[64];
    const char* ptr = (const char*)pgm_read_word(&(ideaTable[idx]));
    strcpy_P(buf, ptr);
    return String(buf);
}

String getIdea(int index) {
    return (index < FIXED_IDEAS) ? getFixedIdea(index) : serialIdeas[index - FIXED_IDEAS];
}

int getTotalIdeas() {
    int count = 0;
    for (int i = 0; i < FIXED_IDEAS; i++) if (!deletedFlags[i]) count++;
    count += serialIdeaCount;
    return count;
}

int getRandomIdeaIndex() {
    int total = getTotalIdeas();
    if (total == 0) return -1;
    int idx;
    do {
        idx = random(0, FIXED_IDEAS + serialIdeaCount);
    } while ((idx < FIXED_IDEAS && deletedFlags[idx]) && total > 0);
    return idx;
}

void removeCurrentIdea() {
    if (currentIdeaIndex < FIXED_IDEAS) {
        deletedFlags[currentIdeaIndex] = true;
        Serial.print("Removed idea: ");
        Serial.println(getFixedIdea(currentIdeaIndex));
    } else {
        Serial.print("Removed idea: ");
        Serial.println(serialIdeas[currentIdeaIndex - FIXED_IDEAS]);
        for (int i = currentIdeaIndex - FIXED_IDEAS; i < serialIdeaCount - 1; i++)
            serialIdeas[i] = serialIdeas[i + 1];
        serialIdeaCount--;
    }
}

void updateLCD(const char* line0, const char* line1) {
    if (lastLine0 != String(line0)) {
        lcd.setCursor(0, 0); lcd.print("                ");
        lcd.setCursor(0, 0); lcd.print(line0);
        lastLine0 = line0;
    }
    if (lastLine1 != String(line1)) {
        lcd.setCursor(0, 1); lcd.print("                ");
        lcd.setCursor(0, 1); lcd.print(line1);
        lastLine1 = line1;
    }
}

// --- Setup ---
void setup() {
    Serial.begin(9600);
    lcd.init(); 
    lcd.backlight();
    pinMode(buttonTime, INPUT_PULLUP);
    pinMode(buttonIdea, INPUT_PULLUP);
    pinMode(buttonAge, INPUT_PULLUP);

    if (!rtc.begin()) { 
        lcd.clear(); 
        lcd.setCursor(0,0); 
        lcd.print("RTC not found!"); 
        while(1); 
    }

    myServo.attach(servoPin);
    myServo.write(0); 
    lastServoAngle = 0; 
    lastServoMove = millis();
    servoInterval = random(30000, 60000);
    servoIsAttached = true;
    servoDetachTime = millis() + SERVO_HOLD_MS;
    randomSeed(analogRead(A0));

    Serial.println(F("=== Controls & Serial Commands ==="));
    Serial.println(F("Buttons:"));
    Serial.println(F("  Time button : Show current time"));
    Serial.println(F("  Age button  : Show Instructables age"));
    Serial.println(F("  Idea button : Show random idea (short press)"));
    Serial.println(F("                Hold Idea button -> Remove idea prompt"));
    Serial.println(F("Confirm remove: short press toggles, hold to confirm"));
    Serial.println(F("Serial commands:"));
    Serial.println(F("  I <text>    : Add a new idea (case preserved)"));
    Serial.println(F("  L           : List all ideas (indexed)"));
    Serial.println(F("  T hh:mm     : Set the time (24 hour, e.g. T 13:45)"));
    Serial.println(F("  D yyyy/mm/dd: Set the date (e.g. D 2025/09/07)"));
    Serial.println(F("  R           : Reset servo to the forward direction"));
    Serial.println(F("==============================="));
}

// --- Loop ---
void loop() {
    handleButtons();
    handleSerial();
    switch(currentMode) {
        case SHOW_TIME: displayTime(); break;
        case SHOW_AGE: displayInstructablesAge(); break;
        case SHOW_IDEA: displayRandomIdea(currentIdeaIndex); break;
        case CONFIRM_REMOVE: displayConfirmMenu(); break;
    }
    updateServo();
    delay(50);
}
