#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ezButton.h>
#define ENCODER_PIN_A 2
#define ENCODER_PIN_B 3
#define ENCODER_BTN_PIN 4
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
volatile long encoderPosition = 0;
volatile int lastEncoded = 0;
int menuIndex = 0; // 0:W, 1:V, 2:A
const unsigned long blinkInterval = 500; // 0.5초
ezButton encoderBtn(ENCODER_BTN_PIN);
// W 그래프 관련 변수 선언
#define W_GRAPH_WIDTH  (SCREEN_WIDTH / 2)
#define W_GRAPH_HEIGHT SCREEN_HEIGHT
#define W_GRAPH_POINTS 64
float wValues[W_GRAPH_POINTS] = {0};
int wIndex = 0;
bool inWGraphScreen = false;
void handleEncoder()
{
    int MSB = digitalRead(ENCODER_PIN_A);
    int LSB = digitalRead(ENCODER_PIN_B);
    int encoded = (MSB << 1) | LSB;
    int sum = (lastEncoded << 2) | encoded;
    if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011)
        encoderPosition++;
    if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000)
        encoderPosition--;
    lastEncoded = encoded;
}
void drawMenu()
{
    display.clearDisplay();
    // ----- 왼쪽 공식 그림 -----
    int x_offset = -28;
    int cx = 64 + x_offset, cy = 32, r = 30;
    display.drawCircle(cx, cy, r, SSD1306_WHITE);
    display.drawLine(cx - 29, cy, cx + 29, cy, SSD1306_WHITE);
    display.drawLine(cx, cy, cx, cy + 30, SSD1306_WHITE);
    display.setTextSize(2);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(cx - 5, cy - 20);
    display.print("V");
    display.setCursor(cx - 15, cy + 5);
    display.print("I");
    display.setCursor(cx + 7, cy + 5);
    display.print("R");
    // ----- 오른쪽 W/V/A 박스 -----
    int box_height = 20;
    int box_width = 24;
    int box_x_offset = -5;
    int text_x_offset = 7;
    int text_y_offset = 2;
    int x = SCREEN_WIDTH - box_width - 4 + box_x_offset;
    int y_top = 2;
    int y_mid = y_top + box_height;
    int y_bot = y_mid + box_height;
    // W 박스
    if (menuIndex == 0)
        display.fillRect(x, y_top, box_width, box_height, SSD1306_WHITE);
    else
        display.drawRect(x, y_top, box_width, box_height, SSD1306_WHITE);
    display.setTextColor((menuIndex == 0) ? SSD1306_BLACK : SSD1306_WHITE);
    display.setCursor(x + text_x_offset, y_top + text_y_offset);
    display.print("W");
    // V 박스
    if (menuIndex == 1)
        display.fillRect(x, y_mid, box_width, box_height, SSD1306_WHITE);
    else
        display.drawRect(x, y_mid, box_width, box_height, SSD1306_WHITE);
    display.setTextColor((menuIndex == 1) ? SSD1306_BLACK : SSD1306_WHITE);
    display.setCursor(x + text_x_offset, y_mid + text_y_offset);
    display.print("V");
    // A 박스
    if (menuIndex == 2)
        display.fillRect(x, y_bot, box_width, box_height, SSD1306_WHITE);
    else
        display.drawRect(x, y_bot, box_width, box_height, SSD1306_WHITE);
    display.setTextColor((menuIndex == 2) ? SSD1306_BLACK : SSD1306_WHITE);
    display.setCursor(x + text_x_offset, y_bot + text_y_offset);
    display.print("A");
    display.display();
    display.setTextColor(SSD1306_WHITE); // 다음 draw를 위해 복원
}
void drawWGraphScreen(bool blinkBackArrow)
{
    display.clearDisplay();
    // X,Y축 그리기
    display.drawRect(0, 0, W_GRAPH_WIDTH, W_GRAPH_HEIGHT, SSD1306_WHITE);
    display.drawLine(0, W_GRAPH_HEIGHT - 1, W_GRAPH_WIDTH, W_GRAPH_HEIGHT - 1, SSD1306_WHITE); // X축
    display.drawLine(0, 0, 0, W_GRAPH_HEIGHT, SSD1306_WHITE); // Y축
    // W 값 라인그래프 그리기
    for (int i = 1; i < W_GRAPH_POINTS; i++)
    {
        int idx0 = (wIndex + i - 1) % W_GRAPH_POINTS;
        int idx1 = (wIndex + i) % W_GRAPH_POINTS;
        int y0 = W_GRAPH_HEIGHT - 1 - (int)(wValues[idx0] * (W_GRAPH_HEIGHT - 2));
        int y1 = W_GRAPH_HEIGHT - 1 - (int)(wValues[idx1] * (W_GRAPH_HEIGHT - 2));
        display.drawLine(i - 1, y0, i, y1, SSD1306_WHITE);
    }
    // 오른쪽 맨 위에 뒤로가기 화살표와 네모, 색상 반전
    int boxW = 18, boxH = 18;
    int boxX = SCREEN_WIDTH - boxW - 2;
    int boxY = 2;
    if (blinkBackArrow)
        display.fillRect(boxX, boxY, boxW, boxH, SSD1306_WHITE);
    else
        display.drawRect(boxX, boxY, boxW, boxH, SSD1306_WHITE);
    display.setTextSize(2);
    display.setTextColor(blinkBackArrow ? SSD1306_BLACK : SSD1306_WHITE);
    display.setCursor(boxX + 3, boxY + 2);
    display.print("\x1B"); // ←
    display.setTextColor(SSD1306_WHITE); // 복원
    // --- 오른쪽 상단에 실시간 계산식 및 값 표시 ---
    float v = 3.45 + 0.5 * sin(millis() / 1500.0); // 예시 V
    float a = 2.10 + 0.3 * cos(millis() / 1200.0); // 예시 A
    float w = v * a;
    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
    int infoX = W_GRAPH_WIDTH + 4;
    int infoY = 24; // 더 위로 올림
    // 계산식 2줄로 표시
    display.setCursor(infoX, 4);
    display.print("W =");
    display.setCursor(infoX, 16);
    display.print("V x A");
    // 수치 표시
    display.setCursor(infoX, infoY + 6);
    display.print("W: "); display.print(w, 2);
    display.setCursor(infoX, infoY + 18);
    display.print("V: "); display.print(v, 2);
    display.setCursor(infoX, infoY + 30);
    display.print("A: "); display.print(a, 2);
    display.display();
}
void setup()
{
    pinMode(ENCODER_PIN_A, INPUT_PULLUP);
    pinMode(ENCODER_PIN_B, INPUT_PULLUP);
    int MSB = digitalRead(ENCODER_PIN_A);
    int LSB = digitalRead(ENCODER_PIN_B);
    lastEncoded = (MSB << 1) | LSB;
    attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_A), handleEncoder, CHANGE);
    attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_B), handleEncoder, CHANGE);
    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
    display.clearDisplay();
    drawMenu();
    encoderBtn.setDebounceTime(50); // 50ms 디바운스
}
void loop()
{
    static long lastPos = 0;
    static unsigned long lastBlink = 0;
    static bool blinkState = false;
    static unsigned long wScreenBtnPressedTime = 0;
    static bool wScreenEntered = false;
    encoderBtn.loop();
    // 메뉴에서 버튼 눌림 감지 (ezButton 사용)
    if (!inWGraphScreen && menuIndex == 0 && encoderBtn.isPressed())
    {
        inWGraphScreen = true;
        wScreenEntered = true; // 진입 직후
        display.clearDisplay();
        display.display();
    }
    // 메뉴 화면에서 엔코더 회전 처리
    if (!inWGraphScreen) {
        long filteredEncoderPos = encoderPosition / 4;
        if (filteredEncoderPos != lastPos) {
            if (filteredEncoderPos > lastPos) {
                menuIndex = (menuIndex + 1) % 3;
            } else {
                menuIndex = (menuIndex + 2) % 3; // (menuIndex-1+3)%3
            }
            lastPos = filteredEncoderPos;
            drawMenu();
        }
        // 깜빡임 타이머
        if (millis() - lastBlink > blinkInterval) {
            blinkState = !blinkState;
            lastBlink = millis();
            drawMenu();
        }
    }
    if (inWGraphScreen) {
        // 깜빡임 타이머
        if (millis() - lastBlink > blinkInterval) {
            blinkState = !blinkState;
            lastBlink = millis();
        }
        // W값 샘플링 (여기선 예시로 사인파)
        float w = (sin(millis() / 1000.0) + 1.0) / 2.0; // 0~1 범위
        wValues[wIndex] = w;
        wIndex = (wIndex + 1) % W_GRAPH_POINTS;
        drawWGraphScreen(blinkState);
        // 진입 직후에는 버튼이 완전히 떼어질 때까지 복귀 처리 금지
        if (wScreenEntered) {
            if (encoderBtn.isReleased()) {
                wScreenEntered = false;
            }
        } else {
            // 버튼 눌렀다 떼면 복귀
            if (encoderBtn.isPressed()) {
                wScreenBtnPressedTime = millis();
            }
            if (encoderBtn.isReleased()) {
                inWGraphScreen = false;
                drawMenu();
                delay(300); // 복귀시 디바운스
            }
        }
        return;
    }
}