/*
  KLOKKEPROSJEKT 2025
  ====================
  En smart skole-timeplan klokke med NeoPixel LED-ring
  
  Hver elev/gruppe skal implementere sin egen funksjon.
  Alle funksjoner må følge spesifikasjonene nøyaktig!
*/
#include <WiFi.h>
#include <time.h>
#include <Adafruit_NeoPixel.h>
// ========== HARDWARE KONFIGURASJON ==========
#define LED_PIN 25        // Pin for NeoPixel ring
#define NUM_LEDS 60       // Antall LEDs på ringen (60 = en hel sirkel)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
// ========== WIFI KONFIGURASJON ==========
const char* ssid = "Wokwi-GUEST";      // WiFi navn
const char* password = "";               // WiFi passord
// ========== ENUMS OG DATASTRUKTURER ==========
enum Fag {
  INGENTING, FRIMINUTT, ELKRETSER, ELENERGI, STYRESYS, NORSK, ENGELSK, MATTE, NATURFAG, GYM
};
enum Ukedag {
  SONDAG = 0, MANDAG, TIRSDAG, ONSDAG, TORSDAG, FREDAG, LORDAG
};
struct timePlan {
  Ukedag dag;       // Se enum Ukedag
  byte startTime;   // 0-23
  byte startMinutt; // 0-59
  byte varighet;    // Minutter
  Fag fag;          // Enum for fag
};
// ========== GLOBALE VARIABLER ==========
timePlan plan[50];     // Array for hele ukens timeplan
int antallTimer = 48;  // HØYESTE INDEX + 1 (ikke antall elementer!)
Fag gjeldendeFag = INGENTING; // Hvilket fag vi har nå (bruker enum)
Fag forrigeFag = INGENTING;   // Hvilket fag vi hadde før
int sekunderIgjen = 0;        // Sekunder igjen av gjeldende aktivitet
// Status-flagg for animasjoner
bool nyTime = false;
bool nyttFriminutt = false; 
bool ferdigForDagen = false;
bool erHelg = false;
// ========== FUNKSJONSERKLÆRINGER ==========
// Disse funksjonene må elevene implementere:
// ENKLE FUNKSJONER:
bool sjekkHelg(int ukedag);
uint32_t fagFarge(Fag fag);
void blinkLED(uint32_t farge, int antallBlink);
void timeStartAnimasjon();
void friminuttAnimasjon();
// MIDDELS FUNKSJONER:
void visKlokkevisere(int time, int minutt);
void nedtellingBar(int sekunderIgjen, int totalSekunder, uint32_t farge);
void spillMelodi(int melodi);
void ferdigForDagenAnimasjon();
void helgeSluttAnimasjon();
// AVANSERTE FUNKSJONER:
void fyllPlan();
int beregnTidIgjen(int time, int minutt, int sekund, int ukedag);
Fag hentGjeldendeFag(int time, int minutt, int ukedag);
bool hentInternetTid();
void helgAnimasjon();
// ========== HJELPEFUNKSJONER (ferdig implementert) ==========
void debugInfo() {
  time_t now;
  struct tm timeinfo;
  time(&now);
  localtime_r(&now, &timeinfo);
  
  Serial.print("Tid: ");
  Serial.printf("%02d:%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
  Serial.print(" | Ukedag: ");
  Serial.print(timeinfo.tm_wday);
  Serial.print(" | Fag: ");
  Serial.print(gjeldendeFag);
  Serial.print(" | Sekunder igjen: ");
  Serial.println(sekunderIgjen);
}
void startupAnimasjon() {
  // Enkel oppstart-animasjon
  for(int i = 0; i < NUM_LEDS; i++) {
    strip.setPixelColor(i, strip.Color(0, 50, 100));
    strip.show();
    delay(50);
  }
  strip.clear();
  strip.show();
}
// ========== SETUP ==========
void setup() {
  Serial.begin(115200);
  Serial.println("🕐 KLOKKEPROSJEKT STARTER...");
  
  // Initialiser LED-strip
  strip.begin();
  strip.show();
  startupAnimasjon();
  
  // Koble til WiFi og hent tid
  if(hentInternetTid()) {
    Serial.println("✅ WiFi og tid OK!");
    blinkLED(strip.Color(0, 255, 0), 3); // Grønn = success
  } else {
    Serial.println("❌ WiFi eller tid feilet!");
    blinkLED(strip.Color(255, 0, 0), 5); // Rød = feil
  }
  
  // Lag timeplan
  fyllPlan();
  Serial.println("📅 Timeplan lastet!");
  
  Serial.println("🚀 Klokke klar!");
}
// ========== HOVEDLOOP ==========
void loop() {
  // Hent gjeldende tid
  time_t now;
  struct tm timeinfo;
  time(&now);
  localtime_r(&now, &timeinfo);
  
  // Sjekk om det er helg
  if(sjekkHelg(timeinfo.tm_wday)) {
    if(!erHelg) {
      erHelg = true;
      Serial.println("🎉 DET ER HELG!");
    }
    helgAnimasjon();
    delay(1000);
    return;
  } else {
    erHelg = false;
  }
  
  // Beregn gjeldende fag og tid igjen
  Fag nyttFag = hentGjeldendeFag(timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_wday);
  sekunderIgjen = beregnTidIgjen(timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, timeinfo.tm_wday);
  
  // Sjekk om vi har byttet aktivitet
  if(nyttFag != forrigeFag) {
    Serial.println("🔄 NY AKTIVITET!");
    
    if(nyttFag == INGENTING) {
      ferdigForDagen = true;
      Serial.println("🏠 Ferdig for dagen!");
      
      // Sjekk om det er siste time på fredag (helgesluttanimasjon)
      if(timeinfo.tm_wday == FREDAG && forrigeFag != INGENTING) {
        helgeSluttAnimasjon();
      }
    } else if(nyttFag == FRIMINUTT) {
      nyttFriminutt = true;
      spillMelodi(1); // Friminutt-melodi
      Serial.println("☕ FRIMINUTT!");
    } else {
      nyTime = true;
      spillMelodi(2); // Time-melodi
      Serial.println("📚 NY TIME!");
    }
    
    forrigeFag = nyttFag;
  }
  
  gjeldendeFag = nyttFag;
  
  // Vis status på LED-ring
  strip.clear();
  
  if(ferdigForDagen) {
    // Vis "ferdig for dagen" animasjon
    ferdigForDagenAnimasjon();
    ferdigForDagen = false;
  } else if(nyttFriminutt) {
    // Vis friminutt-animasjon
    friminuttAnimasjon();
    nyttFriminutt = false;
  } else if(nyTime) {
    // Vis time-start animasjon
    timeStartAnimasjon();
    nyTime = false;
  } else {
    // Normal visning: nedtelling-bue + klokkevisere
    nedtellingBar(sekunderIgjen, 3600, fagFarge(gjeldendeFag)); // Vis gjenværende tid som bue
    visKlokkevisere(timeinfo.tm_hour, timeinfo.tm_min);
  }
  
  strip.show();
  
  // Debug info hver 5. sekund
  static unsigned long lastDebug = 0;
  if(millis() - lastDebug > 5000) {
    debugInfo();
    lastDebug = millis();
  }
  
  delay(1000); // Oppdater hvert sekund
}
// ========== FUNKSJONSIMPLEMENTASJONER ==========
// ELEVENE MÅ IMPLEMENTERE DISSE FUNKSJONENE:
bool sjekkHelg(int ukedag) {
  // TODO: Implementer denne funksjonen
  // Input: ukedag (0=søndag, 1=mandag, ..., 6=lørdag)
  // Output: true hvis det er helg (lørdag eller søndag)
  
  // TIPS til implementering:
  // - Bruk if-setning eller switch-case
  // - Husk: søndag = 0, lørdag = 6
  // - Returner true for helg, false for ukedag
  // - Bare 2-3 linjer kode trengs!
  
  return false; // Placeholder - endre denne når du implementerer!
}
uint32_t fagFarge(Fag fag) {
  // TODO: Implementer denne funksjonen
  // Input: fag (enum Fag: INGENTING, FRIMINUTT, ELKRETSER, etc.)
  // Output: Farge som uint32_t (bruk strip.Color(r,g,b))
  
  // TIPS til implementering:
  // - Bruk switch-case setning med alle fag-enum verdiene
  // - Eksempel farger: FRIMINUTT=grønn(0,255,0), NORSK=rød(255,0,0)
  // - ELKRETSER=turkis(102,205,170), MATTE=mørk grønn(0,100,0)
  // - ENGELSK=lys grønn(60,179,113), GYM=oransje(255,165,0)
  // - NATURFAG=lys rosa(188,143,143), INGENTING=svart(0,0,0)
  // - Husk default-case for ukjente fag!
  
  return 0;        // Svart (placeholder) - endre denne når du implementerer!
}
void blinkLED(uint32_t farge, int antallBlink) {
  // TODO: Implementer denne funksjonen
  // Input: farge og hvor mange ganger den skal blinke
  // Skal blinke hele LED-ringen
  
  // TIPS til implementering:
  // 1. Bruk for-loop for antall blink
  // 2. Tenn alle LEDs: strip.fill(farge)
  // 3. Vis endringen: strip.show()
  // 4. Vent litt: delay(200)
  // 5. Slukk alle LEDs: strip.clear()
  // 6. Vis endringen: strip.show()
  // 7. Vent litt: delay(200)
  // 8. Gjenta for antall ganger spesifisert
  
  // Placeholder - implementer logikken over!
}
void timeStartAnimasjon() {
  // TODO: Implementer denne funksjonen
  // Vis en kort animasjon når en ny time starter (Maks 5 sekunder)
  
  // TIPS til implementering:
  // - Enkel og kort animasjon som signaliserer ny time
  // - Bruk fagFarge(gjeldendeFag) for å vise riktig farge
  // - Eksempel: Puls-effekt, spiraleffekt, eller "countdown" fra sentrum
  // - Kan kombinere med spillMelodi() for ekstra effekt
  // - Hold deg under 5 sekunder total tid!
  
  // Placeholder - implementer en kul time-start animasjon!
}
void friminuttAnimasjon() {
  // TODO: Implementer denne funksjonen
  // Vis en kort animasjon når friminutt starter (Maks 5 sekunder)
  
  // TIPS til implementering:
  // - Glad og energisk animasjon som signaliserer pause
  // - Bruk gjerne grønne farger (friminutt = grønn)
  // - Eksempel: Sprettende "ball", regnbue-flash, eller tilfeldige blitz
  // - Kan kombinere med spillMelodi() for ekstra effekt
  // - Hold deg under 5 sekunder total tid!
  
  // Placeholder - implementer en glad friminutt-animasjon!
}
void visKlokkevisere(int time, int minutt) {
  // TODO: Implementer denne funksjonen
  // Input: time (0-23) og minutt (0-59)
  // Vis timeviser (grønn) og minuttviser (rød) på LED-ringen
  
  // TIPS til implementering:
  // 1. Beregn timeviser posisjon: map(time % 12 * 60 + minutt, 0, 720, 0, NUM_LEDS-1)
  // 2. Beregn minuttviser posisjon: map(minutt, 0, 59, 0, NUM_LEDS-1)
  // 3. Sett timeviser: strip.setPixelColor(timePixel, strip.Color(0, 255, 0))
  // 4. Sett minuttviser: strip.setPixelColor(minuttPixel, strip.Color(255, 0, 0))
  // 5. Hvis begge visere på samme LED, bland fargene eller velg en
  // 6. Timeviser skal bevege seg gradvis, ikke hoppe hver time!
  // 7. VIKTIG: Bruk map() for å tilpasse til NUM_LEDS (fungerer med 12, 24, 60 LEDs etc.)
  
  // Placeholder - implementer logikken over!
}
void nedtellingBar(int sekunderIgjen, int totalSekunder, uint32_t farge) {
  // TODO: Implementer denne funksjonen
  // Input: sekunder igjen, total tid, farge
  // Vis gjenværende tid som en "bue" på klokka
  
  // TIPS til implementering:
  // 1. Beregn gjeldende minutt: (totalSekunder - sekunderIgjen) / 60
  // 2. Beregn slutt-minutt: totalSekunder / 60
  // 3. Konverter til LED-posisjoner: map(minutt, 0, 59, 0, NUM_LEDS-1)
  // 4. Tenn LEDs fra gjeldende posisjon til slutt-posisjon
  // 5. Eksempel: Klokka 11:05, time til 11:30 → tenn fra LED pos for 5min til 30min
  // 6. Bruk for-loop fra startPos til sluttPos
  // 7. Hvis buen går over "midnatt" (siste LED → første LED), håndter dette spesielt
  // 8. VIKTIG: map() gjør at dette fungerer med alle LED-størrelser (12, 24, 60 etc.)
  
  // Placeholder - implementer den nye klokke-baserte logikken over!
}
void spillMelodi(int melodi) {
  // TODO: Implementer denne funksjonen
  // Input: melodi-nummer (1=friminutt, 2=time, etc.)
  // Spill en melodi (kan være tom implementasjon hvis ingen buzzer)
  
  // TIPS til implementering - ALTERNATIV 1 (med buzzer):
  // - Definer BUZZER_PIN og bruk tone(pin, frekvens, varighet)
  // - Friminutt: Glad melodi (høye toner)
  // - Time: Nøytral tone (middels toner)
  //
  // TIPS til implementering - ALTERNATIV 2 (uten buzzer):
  // - Bruk LED-signaler i stedet for lyd
  // - Friminutt: blinkLED(strip.Color(0, 255, 0), 3) // Grønn
  // - Time: blinkLED(strip.Color(255, 0, 0), 2) // Rød
  // - Lag forskjellige blinkmønstre for hver melodi
  
  // Placeholder - velg alternativ og implementer!
}
void ferdigForDagenAnimasjon() {
  // TODO: Implementer denne funksjonen
  // Vis en animasjon når skoledagen er ferdig (Maks 10 sekunder)
  
  // TIPS til implementering:
  // - Avslappende og rolig animasjon som signaliserer at dagen er over
  // - Bruk myke farger som fade inn/ut
  // - Eksempel: Solnedgang-effekt, bølgeanimasjon, eller spirende "godnattstjerner"
  // - Kan starte intenst og fade til svart på slutten
  // - Maksimalt 10 sekunder - bruk tiden godt!
  // - Kombiner gjerne forskjellige effekter
  
  // Placeholder - implementer en rolig "ferdig for dagen" animasjon!
}
void helgeSluttAnimasjon() {
  // TODO: Implementer denne funksjonen
  // Vis en spektakulær animasjon når siste time på fredag er ferdig (Maks 30 sekunder)
  
  // TIPS til implementering:
  // - Dette er den store celebrasjonen - vær kreativ og spektakulær!
  // - Kombiner flere effekter: fyrverkeri, regnbuer, puls, rotasjoner
  // - Bruk alle 30 sekunder for en episk opplevelse
  // - Start rolig og bygg opp til klimaks
  // - Eksempel: Fyrverkeri → regnbue → feiring → rolig slutt
  // - Bruk math-funksjoner for smooth overganger
  // - Dette er eleven sin sjanse til å virkelig skinne!
  
  // Placeholder - implementer en episk helgesluttanimasjon!
}
void fyllPlan() {
  // MERK: Det er OK å ha hull i listen! Vi bruker forskjellige indekser for hver dag.
  
  // Mandag (0-9)
  plan[0] = {MANDAG, 10, 0, 90, STYRESYS};
  plan[1] = {MANDAG, 11, 30, 30, FRIMINUTT};
  plan[2] = {MANDAG, 12, 0, 45, STYRESYS};
  plan[3] = {MANDAG, 12, 45, 45, ENGELSK};
  plan[4] = {MANDAG, 13, 30, 10, FRIMINUTT};
  plan[5] = {MANDAG, 13, 40, 90, ENGELSK};
  // Tirsdag (10-19)
  plan[10] = {TIRSDAG, 8, 10, 90, ENGELSK};
  plan[11] = {TIRSDAG, 9, 40, 20, FRIMINUTT};
  plan[12] = {TIRSDAG, 10, 0, 90, MATTE};
  plan[13] = {TIRSDAG, 11, 30, 30, FRIMINUTT};
  plan[14] = {TIRSDAG, 12, 0, 90, NORSK};
  plan[15] = {TIRSDAG, 13, 30, 10, FRIMINUTT};
  plan[16] = {TIRSDAG, 13, 40, 90, STYRESYS};
  // Onsdag (20-29) - MERK: Fikset feil dag fra FREDAG til ONSDAG
  plan[20] = {ONSDAG, 8, 10, 90, STYRESYS};
  plan[21] = {ONSDAG, 9, 40, 20, FRIMINUTT};
  plan[22] = {ONSDAG, 10, 0, 90, STYRESYS};
  plan[23] = {ONSDAG, 11, 30, 30, FRIMINUTT};
  plan[24] = {ONSDAG, 12, 0, 45, STYRESYS};
  // Torsdag (30-39)
  plan[30] = {TORSDAG, 8, 10, 90, NORSK};
  plan[31] = {TORSDAG, 9, 40, 20, FRIMINUTT};
  plan[32] = {TORSDAG, 10, 00, 90, ELKRETSER};
  plan[33] = {TORSDAG, 11, 30, 30, FRIMINUTT};
  plan[34] = {TORSDAG, 12, 0, 90, GYM};
  plan[35] = {TORSDAG, 13, 30, 10, FRIMINUTT};
  plan[36] = {TORSDAG, 13, 40, 90, STYRESYS};
  // Fredag (40-49)
  plan[40] = {FREDAG, 8, 10, 90, NATURFAG};
  plan[41] = {FREDAG, 9, 40, 20, FRIMINUTT};
  plan[42] = {FREDAG, 10, 0, 90, MATTE};
  plan[43] = {FREDAG, 11, 30, 30, FRIMINUTT};
  plan[44] = {FREDAG, 12, 0, 45, MATTE};
  plan[45] = {FREDAG, 12, 45, 90, STYRESYS};
  plan[46] = {FREDAG, 13, 30, 10, FRIMINUTT};
  plan[47] = {FREDAG, 13, 40, 90, STYRESYS};
  
  // antallTimer er nå 48 (høyeste index + 1)
}
Fag hentGjeldendeFag(int time, int minutt, int ukedag) {
  // TODO: Implementer denne funksjonen
  // Input: gjeldende tid og ukedag
  // Output: hvilket fag vi har nå (enum Fag)
  
  // TIPS til implementering:
  // 1. Konverter gjeldende tid til minutter: time * 60 + minutt
  // 2. Søk gjennom plan[] arrayet (index 0 til 49)
  // 3. For hver oppføring, sjekk om plan[i].dag == ukedag
  // 4. Beregn starttid i minutter: plan[i].startTime * 60 + plan[i].startMinutt
  // 5. Beregn slutttid: starttid + plan[i].varighet
  // 6. Sjekk om gjeldende tid er mellom start og slutt
  // 7. Hvis ja: returner plan[i].fag
  // 8. Hvis ingen match: returner INGENTING
  
  return INGENTING; // Placeholder - endre denne når du implementerer!
}
int beregnTidIgjen(int time, int minutt, int sekund, int ukedag) {
  // TODO: Implementer denne funksjonen
  // Input: gjeldende tid og ukedag
  // Output: hvor mange sekunder som er igjen av gjeldende aktivitet
  
  // TIPS til implementering:
  // 1. Konverter gjeldende tid til sekunder: time * 3600 + minutt * 60 + sekund
  // 2. Søk gjennom plan[] arrayet (index 0 til 49)
  // 3. For hver oppføring, sjekk om plan[i].dag == ukedag
  // 4. Beregn starttid i sekunder: plan[i].startTime * 3600 + plan[i].startMinutt * 60
  // 5. Beregn slutttid: starttid + (plan[i].varighet * 60)
  // 6. Sjekk om gjeldende tid er mellom start og slutt
  // 7. Hvis ja: returner (slutttid - gjeldende tid)
  // 8. Hvis ingen match: returner 0
  
  return 0; // Placeholder - endre denne når du implementerer!
}
bool hentInternetTid() {
  // TODO: Implementer denne funksjonen
  // Skal koble til WiFi og hente tid fra NTP-server
  // Output: true hvis successful, false hvis feil
  
  // TIPS til implementering:
  // 1. Koble til WiFi: WiFi.begin(ssid, password)
  // 2. Vent på tilkobling med timeout (ikke evig!)
  // 3. Sjekk status: WiFi.status() == WL_CONNECTED
  // 4. Sett tidssone: configTime(3600, 3600, "pool.ntp.org")
  // 5. Vent litt på tidssynkronisering: delay(2000)
  // 6. Sjekk at vi fikk gyldig tid: time(&now); return (now > 1000000)
  // 7. Håndter feil gracefully, returner false hvis noe går galt
  // 8. Bruk Serial.print() for debugging
  
  return false; // Placeholder - implementer logikken over!
}
void helgAnimasjon() {
  // TODO: Implementer denne funksjonen
  // Lag en kul animasjon som vises i helgene
  
  // TIPS til implementering - Vær kreativ! Dette er din sjanse til å skinne:
  // - Regnbue-effekter: Bruk forskjellige farger som roterer
  // - Bouncing balls: Simuler en ball som spretter
  // - Fade-effekter: Fade inn/ut med forskjellige farger
  // - Roterende mønstre: Roter et mønster rundt ringen
  // - Stjernehimmel: Tilfeldige LEDs som blinker som stjerner
  // - Fyrverk-effekt: Eksplosjoner av farger
  // - Bruk math-funksjoner som sin(), cos() for smooth animasjoner
  // - Kombiner forskjellige effekter!
  // - Husk: ikke bruk for lange delays (animasjonen kalles hver loop)
  
  // Placeholder - vær kreativ og implementer din egen kule animasjon!
}