#include <Arduino.h>
#include <math.h>
#include <time.h>
#include "PortalManager.h"

PortalManager::PortalManager()
  : lastColorChange(0),
    lastGlyphChange(0),
    currentColorIndex(0)
{
    for (int i = 0; i < NUM_PORTALS; i++) {
        screens[i] = nullptr;
        currentGlyphOffset[i] = i * 5;  // Chaque portail démarre avec un glyphe différent
    }
    
    initPalettes();
}

void PortalManager::attach(int index, LGFX_Portal* screen) {
    if (index < 0 || index >= NUM_PORTALS) return;
    screens[index] = screen;
}

// Génération des palettes de couleurs
void PortalManager::initPalettes() {
    // Palette FROIDE (mode repos) - tons apaisants
    coldPalette.name = "COLD";
    coldPalette.colors[0]  = rgb565(0, 100, 180);    // Bleu profond
    coldPalette.colors[1]  = rgb565(0, 150, 200);    // Cyan
    coldPalette.colors[2]  = rgb565(0, 180, 160);    // Turquoise
    coldPalette.colors[3]  = rgb565(0, 200, 120);    // Vert-cyan
    coldPalette.colors[4]  = rgb565(40, 160, 200);   // Bleu ciel
    coldPalette.colors[5]  = rgb565(60, 120, 220);   // Bleu électrique
    coldPalette.colors[6]  = rgb565(80, 80, 200);    // Indigo
    coldPalette.colors[7]  = rgb565(100, 60, 180);   // Violet doux
    coldPalette.colors[8]  = rgb565(0, 120, 140);    // Teal profond
    coldPalette.colors[9]  = rgb565(0, 160, 180);    // Cyan clair
    coldPalette.colors[10] = rgb565(20, 140, 160);   // Bleu-vert
    coldPalette.colors[11] = rgb565(60, 100, 180);   // Bleu lavande

    // Palette CHAUDE (mode présence) - tons vibrants
    warmPalette.name = "WARM";
    warmPalette.colors[0]  = rgb565(255, 0, 100);    // Rose vif
    warmPalette.colors[1]  = rgb565(255, 0, 150);    // Magenta
    warmPalette.colors[2]  = rgb565(220, 0, 200);    // Magenta-violet
    warmPalette.colors[3]  = rgb565(180, 0, 220);    // Violet électrique
    warmPalette.colors[4]  = rgb565(160, 0, 200);    // Violet profond
    warmPalette.colors[5]  = rgb565(200, 0, 180);    // Mauve
    warmPalette.colors[6]  = rgb565(255, 40, 120);   // Rose-orange
    warmPalette.colors[7]  = rgb565(255, 80, 0);     // Orange vif
    warmPalette.colors[8]  = rgb565(255, 100, 50);   // Orange clair
    warmPalette.colors[9]  = rgb565(200, 50, 150);   // Fuchsia
    warmPalette.colors[10] = rgb565(180, 20, 180);   // Violet pur
    warmPalette.colors[11] = rgb565(220, 60, 120);   // Rose-mauve
}

uint16_t PortalManager::rgb565(uint8_t r, uint8_t g, uint8_t b) {
    return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}

uint8_t PortalManager::lerp(uint8_t a, uint8_t b, float t) {
    return a + (b - a) * t;
}

// ===============================================================
// INTERPOLATION DE COULEUR SELON LA PRÉSENCE (GRADIENT FLUIDE)
// ===============================================================
uint16_t PortalManager::getGradientColor(float presence, int colorIndex) {
    // Extraction des composantes RGB de la palette froide
    uint16_t coldColor = coldPalette.colors[colorIndex % 12];
    uint8_t r1 = ((coldColor >> 11) & 0x1F) << 3;  // 5 bits → 8 bits
    uint8_t g1 = ((coldColor >> 5) & 0x3F) << 2;   // 6 bits → 8 bits
    uint8_t b1 = (coldColor & 0x1F) << 3;          // 5 bits → 8 bits
    
    // Extraction des composantes RGB de la palette chaude
    uint16_t warmColor = warmPalette.colors[colorIndex % 12];
    uint8_t r2 = ((warmColor >> 11) & 0x1F) << 3;
    uint8_t g2 = ((warmColor >> 5) & 0x3F) << 2;
    uint8_t b2 = (warmColor & 0x1F) << 3;
    
    // Interpolation linéaire basée sur la présence (0.0 = froid, 1.0 = chaud)
    uint8_t r = lerp(r1, r2, presence);
    uint8_t g = lerp(g1, g2, presence);
    uint8_t b = lerp(b1, b2, presence);
    
    return rgb565(r, g, b);
}

// ===============================================================
// MISE À JOUR DU PORTAIL AVEC PAGES COLORÉES
// ===============================================================
void PortalManager::updatePortal(LGFX_Portal* p, int portalIndex, float presence) {
    if (!p) return;
    if (portalIndex < 0 || portalIndex >= NUM_PORTALS) return;

    unsigned long now = millis();
    
    // ===== VITESSES VARIABLES SELON LA PRÉSENCE =====
    // Plus la présence est forte, plus ça tourne vite
    // presence = 0.0 (loin)  → 10s couleur, 5s glyphe
    // presence = 0.5 (moyen) → 6s couleur, 3s glyphe  
    // presence = 1.0 (proche)→ 2s couleur, 1s glyphe
    
    unsigned long colorDuration = 10000 - (presence * 8000);  // 10s → 2s
    unsigned long glyphDuration = 5000 - (presence * 4000);   // 5s → 1s
    
    // ===== ROTATION DES COULEURS =====
    if (now - lastColorChange >= colorDuration) {
        lastColorChange = now;
        currentColorIndex = (currentColorIndex + 1) % 12;
        
        // Estimation distance : baseline(300mm) - presence*(250mm) puis /10 pour cm
        float distCM = (300.0f - (presence * 250.0f)) / 10.0f;
        
        Serial.printf("🎨 Couleur #%d | Présence: %.2f (~%.1fcm)\n", 
                      currentColorIndex, 
                      presence,
                      distCM);
    }
    
    // ===== ROTATION DES GLYPHES =====
    if (now - lastGlyphChange >= glyphDuration) {
        lastGlyphChange = now;
        for (int i = 0; i < NUM_PORTALS; i++) {
            currentGlyphOffset[i] = (currentGlyphOffset[i] + 1) % TOTAL_GLYPHS;
        }
    }

    // ===== RENDU DU PORTAIL =====
    
    // Chaque portail a une couleur légèrement décalée
    int colorOffset = (currentColorIndex + portalIndex * 2) % 12;
    
    // **GRADIENT DE COULEUR SELON LA PRÉSENCE**
    uint16_t mainColor = getGradientColor(presence, colorOffset);
    
    // **FOND NOIR**
    p->fillScreen(0x0000);
    
    const int cx = 120;
    const int cy = 120;
    
    // ===== ANNEAUX COLORÉS CONCENTRIQUES =====
    // Intensité de la pulsation augmente avec la présence
    float pulseSpeed = 0.002f + (presence * 0.008f);  // 0.002 → 0.010
    float pulse = sinf(now * pulseSpeed);
    
    // Anneau extérieur (grand)
    int r1 = 110 + pulse * (8 + presence * 12);  // Amplitude augmente
    for (int i = 0; i < 360; i += 3) {
        float rad = i * DEG_TO_RAD;
        int x1 = cx + cosf(rad) * r1;
        int y1 = cy + sinf(rad) * r1;
        p->drawPixel(x1, y1, mainColor);
    }
    
    // Anneau moyen
    int r2 = 85 + pulse * (5 + presence * 8);
    for (int i = 0; i < 360; i += 2) {
        float rad = i * DEG_TO_RAD;
        int x2 = cx + cosf(rad) * r2;
        int y2 = cy + sinf(rad) * r2;
        p->drawPixel(x2, y2, mainColor);
    }
    
    // Anneau intérieur (plus dense)
    int r3 = 60 + pulse * (3 + presence * 5);
    p->drawCircle(cx, cy, r3, mainColor);
    
    // ===== RAYONS COLORÉS =====
    // Vitesse de rotation augmente avec la présence
    float raySpeed = 0.05f + (presence * 0.15f);  // 0.05 → 0.20
    for (int i = 0; i < 8; i++) {
        float angle = (i * 45.0f + now * raySpeed) * DEG_TO_RAD;
        int startR = 50;
        int endR = 95;
        
        // Rayon avec plusieurs pixels
        for (int r = startR; r < endR; r += 4) {
            int px = cx + cosf(angle) * r;
            int py = cy + sinf(angle) * r;
            p->drawPixel(px, py, mainColor);
        }
    }
    
    // ===== PARTICULES ORBITALES COLORÉES =====
    // Nombre augmente graduellement avec la présence
    int numParticles = 6 + (int)(presence * 6);  // 6 → 12
    float orbitSpeed = 0.1f + (presence * 0.2f);  // 0.1 → 0.3
    
    for (int i = 0; i < numParticles; i++) {
        float orbitAngle = (i * (360.0f / numParticles) + now * orbitSpeed) * DEG_TO_RAD;
        int orbitRadius = 75;
        int px = cx + cosf(orbitAngle) * orbitRadius;
        int py = cy + sinf(orbitAngle) * orbitRadius;
        p->fillCircle(px, py, 2, mainColor);
    }
    
    // ===== HIÉROGLYPHE CENTRAL BLANC =====
    const int glyphSize = 60;
    
    // Glyphe actuel pour ce portail
    int glyphId = currentGlyphOffset[portalIndex];
    
    // Couleur du glyphe : blanc, intensité augmente avec présence
    uint8_t whiteIntensity = 200 + (uint8_t)(presence * 55);  // 200 → 255
    uint32_t glyphColor = p->color565(whiteIntensity, whiteIntensity, whiteIntensity);
    
    // Effet de pulsation plus rapide avec présence
    float glyphPulseSpeed = 0.003f + (presence * 0.007f);
    float glyphPulse = 0.85f + 0.15f * sinf(now * glyphPulseSpeed);
    int actualSize = glyphSize * glyphPulse;
    
    drawGlyph(p, 
              cx - actualSize / 2, 
              cy - actualSize / 2, 
              actualSize, 
              glyphColor, 
              glyphId);
}


// ===============================================================
// 30 GLYPHES HIÉROGLYPHIQUES (identiques au ST7796)
// ===============================================================
void PortalManager::drawGlyph(LGFX_Portal* t, int x, int y, int size, uint32_t color, int glyphType) {
    int cx = x + size / 2;
    int cy = y + size / 2;
    int r  = size / 2;

    switch (glyphType % 30) {
        case 0: {
            t->drawTriangle(cx, y + 2, x + 2, y + r + 2, x + size - 2, y + r + 2, color);
            t->drawCircle(cx, cy, r - 4, color);
            t->fillCircle(cx, cy, 2, color);
            break;
        }
        case 1: {
            for (int i = 0; i < 6; i++) {
                int x1 = x + 2 + i * 2;
                int y1 = cy + sinf(i * 0.8f) * (r - 2);
                t->fillCircle(x1, y1, 1, color);
            }
            t->fillCircle(x + size - 3, cy, 2, color);
            break;
        }
        case 2: {
            t->drawCircle(cx, cy, r - 2, color);
            for (int a = 0; a < 360; a += 45) {
                float rad = a * DEG_TO_RAD;
                int x1 = cx + cosf(rad) * (r - 5);
                int y1 = cy + sinf(rad) * (r - 5);
                int x2 = cx + cosf(rad) * r;
                int y2 = cy + sinf(rad) * r;
                t->drawLine(x1, y1, x2, y2, color);
            }
            break;
        }
        case 3: {
            for (int a = 180; a <= 360; a += 8) {
                float rad = a * DEG_TO_RAD;
                int px = cx + cosf(rad) * (r - 2);
                int py = cy - 2 + sinf(rad) * (r - 2);
                t->drawPixel(px, py, color);
            }
            t->drawLine(cx - 4, cy, cx + 4, cy, color);
            t->drawLine(cx, cy - 4, cx, cy + 4, color);
            break;
        }
        case 4: {
            for (int wave = 0; wave < 3; wave++) {
                int baseY = y + 4 + wave * 4;
                for (int i = 0; i < size - 4; i++) {
                    int wy = baseY + sinf(i * 0.4f) * 2;
                    t->drawPixel(x + 2 + i, wy, color);
                }
            }
            break;
        }
        case 5: {
            t->drawCircle(cx, cy, r - 4, color);
            t->drawLine(cx - r + 4, cy - 2, cx - 2, y + 2, color);
            t->drawLine(cx + r - 4, cy - 2, cx + 2, y + 2, color);
            break;
        }
        case 6: {
            for (int i = 0; i < 8; i++) {
                int px = x + 3 + i;
                int py = y + 3 + i / 2;
                t->drawPixel(px, py, color);
            }
            t->drawCircle(x + size - 4, y + size - 4, 3, color);
            break;
        }
        case 7: {
            for (int i = 0; i < 5; i++) {
                int sx = x + 2 + i * 2;
                int sy = cy + sinf(i * 0.5f) * 3;
                t->fillCircle(sx, sy, 1, color);
            }
            t->drawLine(cx + 4, cy, x + size - 2, cy - 4, color);
            break;
        }
        case 8: {
            t->drawCircle(cx, cy, r - 4, color);
            for (int a = 0; a < 360; a += 40) {
                float rad = a * DEG_TO_RAD;
                int x2 = cx + cosf(rad) * r;
                int y2 = cy + sinf(rad) * r;
                t->drawLine(cx, cy, x2, y2, color);
            }
            break;
        }
        case 9: {
            float angle = 0;
            int lastX = cx, lastY = cy;
            for (int i = 0; i < 8; i++) {
                angle += 0.6f;
                int radius = 1 + i;
                int sx = cx + cosf(angle) * radius;
                int sy = cy + sinf(angle) * radius;
                t->drawLine(lastX, lastY, sx, sy, color);
                lastX = sx; lastY = sy;
            }
            break;
        }
        case 10: {
            t->drawLine(cx, y + 2, cx, y + size - 2, color);
            for (int w = 0; w < 4; w++) {
                int wing = 2 + w * 2;
                t->drawLine(cx, cy - w, cx - wing, cy - w - 1, color);
                t->drawLine(cx, cy - w, cx + wing, cy - w - 1, color);
            }
            break;
        }
        case 11: {
            int p[5][2] = {{cx-3,cy-3},{cx+3,cy-3},{cx,cy},{cx-3,cy+3},{cx+3,cy+3}};
            for (int i = 0; i < 5; i++) t->fillCircle(p[i][0], p[i][1], 1, color);
            t->drawLine(p[0][0], p[0][1], p[2][0], p[2][1], color);
            t->drawLine(p[1][0], p[1][1], p[2][0], p[2][1], color);
            t->drawLine(p[2][0], p[2][1], p[3][0], p[3][1], color);
            t->drawLine(p[2][0], p[2][1], p[4][0], p[4][1], color);
            break;
        }
        case 12: {
            t->drawLine(cx, y + 3, cx, y + size - 2, color);
            t->drawLine(cx - 4, y + 5, cx, y + 2, color);
            t->drawLine(cx + 4, y + 5, cx, y + 2, color);
            break;
        }
        case 13: {
            t->drawCircle(cx, cy, r - 3, color);
            t->fillCircle(cx, cy, 2, color);
            t->drawLine(x + 2, cy, x, cy, color);
            t->drawLine(x + size - 2, cy, x + size, cy, color);
            break;
        }
        case 14: {
            for (int i = 0; i < 5; i++) {
                float rad = (i * 72.0f) * DEG_TO_RAD - HALF_PI;
                int x1 = cx + cosf(rad) * r;
                int y1 = cy + sinf(rad) * r;
                t->drawLine(cx, cy, x1, y1, color);
            }
            break;
        }
        case 15: {
            t->drawLine(cx, y + 2, cx, y + size - 4, color);
            t->drawCircle(cx, y + size - 5, 3, color);
            t->drawLine(cx - 4, y + size - 5, cx - 6, y + size - 3, color);
            t->drawLine(cx + 4, y + size - 5, cx + 6, y + size - 3, color);
            break;
        }
        case 16: {
            t->fillCircle(cx - 3, cy - 2, 3, color);
            t->fillCircle(cx + 3, cy - 2, 3, color);
            t->fillCircle(cx - 3, cy + 2, 3, color);
            t->fillCircle(cx + 3, cy + 2, 3, color);
            t->drawLine(cx, y + 2, cx, y + size - 2, color);
            break;
        }
        case 17: {
            t->drawLine(cx, y + size - 2, cx, y + 4, color);
            t->drawLine(cx, y + 4, x + 2, y + 6, color);
            t->drawLine(cx, y + 4, x + size - 2, y + 6, color);
            break;
        }
        case 18: {
            for (int a = 0; a < 360; a += 10) {
                float rad = a * DEG_TO_RAD;
                int x1 = cx - 4 + cosf(rad) * 3;
                int y1 = cy + sinf(rad * 2) * 3;
                t->drawPixel(x1, y1, color);
                int x2 = cx + 4 + cosf(rad) * 3;
                t->drawPixel(x2, y1, color);
            }
            break;
        }
        case 19: {
            for (int i = 0; i < 3; i++) {
                int hy = y + 3 + i * 4;
                for (int j = 0; j < 3; j++) {
                    int hx = x + 2 + j * 4 + (i % 2) * 2;
                    t->drawCircle(hx, hy, 2, color);
                }
            }
            break;
        }
        case 20: {
            t->drawLine(cx, y + 2, cx, y + size - 2, color);
            t->drawLine(x + 2, cy, x + size - 2, cy, color);
            t->drawCircle(cx, cy, 3, color);
            break;
        }
        case 21: {
            int points[6][2] = {
                {x+2,cy},{x+4,y+2},{x+7,cy},{x+10,y+2},{x+13,cy},{x+size-2,y+2}
            };
            for (int i = 0; i < 5; i++)
                t->drawLine(points[i][0], points[i][1], points[i+1][0], points[i+1][1], color);
            break;
        }
        case 22: {
            for (int i = 0; i < size - 4; i++) {
                int px = x + 2 + i;
                int py1 = cy + sinf(i * 0.5f) * 3;
                int py2 = cy - sinf(i * 0.5f) * 3;
                t->drawPixel(px, py1, color);
                t->drawPixel(px, py2, color);
            }
            break;
        }
        case 23: {
            t->drawLine(cx, y + 2, x + 2, y + size - 2, color);
            t->drawLine(cx, y + 2, x + size - 2, y + size - 2, color);
            t->drawLine(x + 2, y + size - 2, x + size - 2, y + size - 2, color);
            t->drawLine(cx, y + 2, cx, cy, color);
            break;
        }
        case 24: {
            t->drawLine(x + 2, y + 2, x + size - 2, y + 2, color);
            t->drawLine(x + 2, y + 2, cx, cy, color);
            t->drawLine(x + size - 2, y + 2, cx, cy, color);
            t->drawLine(cx, cy, x + 2, y + size - 2, color);
            t->drawLine(cx, cy, x + size - 2, y + size - 2, color);
            t->drawLine(x + 2, y + size - 2, x + size - 2, y + size - 2, color);
            break;
        }
        case 25: {
            t->drawLine(cx, y + 2, x + 3, cy, color);
            t->drawLine(cx, y + 2, x + size - 3, cy, color);
            t->drawLine(x + 3, cy, cx, y + size - 2, color);
            t->drawLine(x + size - 3, cy, cx, y + size - 2, color);
            break;
        }
        case 26: {
            t->drawCircle(cx, cy, r - 3, color);
            t->fillCircle(cx, cy, 2, color);
            for (int a = 0; a < 360; a += 120) {
                float rad = a * DEG_TO_RAD;
                int ex = cx + cosf(rad) * (r - 3);
                int ey = cy + sinf(rad) * (r - 3);
                t->fillCircle(ex, ey, 1, color);
            }
            break;
        }
        case 27: {
            t->fillCircle(cx, cy - 3, 3, color);
            t->fillCircle(cx - 3, cy, 3, color);
            t->fillCircle(cx + 3, cy, 3, color);
            t->drawLine(cx, cy, cx, y + size - 2, color);
            break;
        }
        case 28: {
            t->drawLine(cx, y + 2, x + 2, cy, color);
            t->drawLine(cx, y + 2, x + size - 2, cy, color);
            t->drawLine(x + 2, cy, x + 3, y + size - 2, color);
            t->drawLine(x + size - 2, cy, x + size - 3, y + size - 2, color);
            t->drawLine(x + 3, y + size - 2, x + size - 3, y + size - 2, color);
            break;
        }
        case 29: {
            t->fillCircle(cx, cy, 3, color);
            for (int a = 0; a < 360; a += 30) {
                float rad = a * DEG_TO_RAD;
                int x1 = cx + cosf(rad) * 4;
                int y1 = cy + sinf(rad) * 4;
                int x2 = cx + cosf(rad) * (r - 1);
                int y2 = cy + sinf(rad) * (r - 1);
                t->drawLine(x1, y1, x2, y2, color);
            }
            break;
        }
    }
}