#include <Adafruit_GFX.h>    // 核心圖形庫
#include <Adafruit_ILI9341.h> // ILI9341硬體專用庫
#include <SPI.h>
#include "mlimage.h"
#include "background.h"
#define TFT_CS  15   // GPIO15 (D8)
#define TFT_RST 4    // GPIO4 (D4)
#define TFT_DC  2    // GPIO2 (D2)
#define JOY_VRX 34   // X軸類比輸入
#define JOY_BTN 35   // 開始按鈕數位輸入
#define JUMP_BTN 32  // 跳躍按鈕數位輸入
#define ATTACK_BTN 33 // 攻擊按鈕數位輸入
#define RESTART_BTN 26 // 重啟按鈕數位輸入
#define TFT_MOSI 23  // 數據針腳
#define TFT_CLK  18  // 時鐘針腳

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

// 玩家變數
int joystickX = analogRead(JOY_VRX);
int a = 0;
int c = 0;
int playerX = 120; // 螢幕中央水平位置
int playerY = 0;
int playerWidth = 10;
int playerHeight = 20;
int groundY;
int lastPlayerX; // 清除軌跡用的上一個X位置
int lastPlayerY; // 清除軌跡用的上一個Y位置
bool isJumping = false;
int jumpVelocity = -12; // 跳躍初速度
float gravity = 0.8; // 重力效應
float currentVelocity = 0;
bool jumpButtonPressed = false;
bool lastJumpButtonState = LOW; // 跳躍按鈕未按下
bool lastAttackButtonState = LOW; // 攻擊按鈕未按下
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50; // 消抖延遲毫秒數
int playerHealth = 100; // 玩家初始血量
bool attackButtonPressed = false; // 攻擊按鈕按下狀態
// 子彈變數
const int maxBullets = 5;
struct Bullet {
  int x, y;
  int lastX, lastY;
  bool isActive;
  int direction; // 1表示右,-1表示左
};
Bullet bullets[maxBullets];
const int bulletSpeed = 5;
const int bulletWidth = 5;
const int bulletHeight = 2;

// 方向變數
int playerDirection = 1; // 1表示右,-1表示左
unsigned long lastDirectionChangeTime = 0; // 上一次方向變化的時間
unsigned long sameDirectionDuration = 0; // 持續同一方向的時間
const unsigned long directionThreshold = 2000; // 持續同一方向的閾值(毫秒)
bool enemySlowed = false; // 用於標記敵人是否變慢

// 敵人變數
int enemyX = 0;
int enemyY = 0;
int enemyWidth = 10;
int enemyHeight = 20;
float enemySpeed = 0.05;  // 放慢敵人速度
bool enemyIsJumping = false;
float enemyJumpVelocity = -12;
float enemyCurrentVelocity = 0;
int enemyHealth = 3; // 敵人血量

const float easingFactor = 0.05;  // 平滑運動係數

const int imageWidth = 640;   // 圖像寬度(螢幕寬度的兩倍)
const int imageHeight = 240;  // 圖像高度

// 滾動變數
int scrollX = 0;  // 初始滾動位置
int scrollSpeed = 1; // 減少滾動速度

// 背景變數
int bgX = 0;  // 背景滾動位置
const int gridSize = 20; // 網格方塊大小
uint16_t buffer[256];
int BMP_WIDTH = 16;
int BMP_HEIGHT = 16;
int TILES_HEIGHT = 1;
int TILES_WIDTH = 1;
int backgroundX = 200;
int backgroundY = 80;

// 平台變數
const int numPlatforms = 6;
int platformX[numPlatforms] = { 150, 250, 300,390,485,585}; // 平台X位置
int platformY[numPlatforms] = { 120, 180, 120,100,80,180}; // 平台Y位置
int platformWidth[numPlatforms] = {30,50,50,40,60,35};
int platformHeight = 10;
int lastPlatformX[numPlatforms]; // 存儲平台上次的位置

// 關卡選擇變數
int selectedLevel = 0;
const int numLevels = 3;
String levelNames[numLevels] = {"ZEUS", "POSEIDON", "HADES"};

// 敵人扣血變數
unsigned long lastDamageTime = 0;
const unsigned long damageInterval = 1000; // 每秒扣血一次

void setup() {
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(ILI9341_BLACK); // 清除屏幕

  // 測試顯示一些基本圖形
  tft.setTextColor(ILI9341_WHITE);

  // 初始化搖桿引腳
  pinMode(JOY_VRX, INPUT);
  pinMode(JOY_BTN, INPUT_PULLUP);
  pinMode(JUMP_BTN, INPUT_PULLUP);
  pinMode(ATTACK_BTN, INPUT_PULLUP);
  pinMode(RESTART_BTN, INPUT_PULLUP);

  // 初始化玩家和地面位置
  groundY = tft.height() - 30;
  playerY = groundY - playerHeight;
  lastPlayerX = playerX;
  lastPlayerY = playerY;
  enemyX = tft.width() - enemyWidth;  // 初始敵人位置
  enemyY = groundY - enemyHeight;     // 與地面同高

  // 初始化子彈
  for (int i = 0; i < maxBullets; i++) {
    bullets[i].isActive = false;
  }

  // 初始化平台位置
  for (int i = 0; i < numPlatforms; i++) {
    lastPlatformX[i] = platformX[i];
  }

  // 顯示開機畫面
  //drawOpeningScreen();
  //waitForStartButton();
  drawLevelSelection();
  waitForLevelSelection();

  tft.fillScreen(ILI9341_BLACK);

  // 繪製地形和平台
  drawTerrain();

  processInput();
  updatePhysics();
  redrawGraphics();
}

void loop() {
  while (true) {
    if (a == 1) {
      drawLevelSelection();
      waitForLevelSelection();

      tft.fillScreen(ILI9341_BLACK);

      // 繪製地形和平台
      drawTerrain();

      processInput();
      updatePhysics();
      redrawGraphics();
      a = 0;
    } else {
      processInput();
      updatePhysics();
      updateBullets();
      redrawGraphics();
      
      delay(10); // 調整此延遲以響應遊戲
      if (playerHealth <= 0) {
        drawGameOverScreen();
        waitForRestartButton();
        restartGame();
        a = 1;
      }
    }
  }
}

void drawOpeningScreen() {
  int x = -bgX;
  int drawX = (x % tft.width());
  tft.fillScreen(ILI9341_BLACK);
  tft.setCursor(10, 10);
  tft.drawRGBBitmap(0, 0, background, 320, 240);
}

void waitForStartButton() {
  while (true) {
    if (digitalRead(JOY_BTN) == LOW) {
      delay(50); // Debounce delay
      if (digitalRead(JOY_BTN) == HIGH) {
        break;
      }
    }
  }
}

void waitForRestartButton() {
  while (true) {
    if (digitalRead(RESTART_BTN) == LOW) {
      delay(50); // Debounce delay
      if (digitalRead(RESTART_BTN) == HIGH) {
        break;
      }
    }
  }
}

void drawLevelSelection() {
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextSize(2);
  tft.setCursor(10, 10);
  tft.setTextColor(ILI9341_WHITE);
  tft.println("SELECT LEVEL:");
  for (int i = 0; i < numLevels; i++) {
    if (i == selectedLevel) {
      tft.setTextColor(ILI9341_YELLOW);
    } else {
      tft.setTextColor(ILI9341_WHITE);
    }
    tft.setCursor(10, 40 + i * 30);
    tft.println(levelNames[i]);
  }
}

void waitForLevelSelection() {
  while (true) {
    int joystickX = analogRead(JOY_VRX);
    if (joystickX < 1500) {
      if (selectedLevel > 0) {
        selectedLevel--;
        drawLevelSelection();
        delay(200); // 防止過快重複輸入
      }
    } else if (joystickX > 2500) {
      if (selectedLevel < numLevels - 1) {
        selectedLevel++;
        drawLevelSelection();
        delay(200); // 防止過快重複輸入
      }
    }

    if (digitalRead(JOY_BTN) == LOW) {
      delay(50); // Debounce delay
      if (digitalRead(JOY_BTN) == HIGH) {
        break;
      }
    }
  }
}

void processInput() {
  bool moved = false;
  int joystickX = analogRead(JOY_VRX);
  float reducedEnemySpeed = 0.005; // 當玩家在邊緣時降低敵人速度

  // 搖桿控制角色移動和背景滾動
  if (joystickX < 1500) {
    if (playerX < tft.width() - 110) { // 恢復原範圍
      playerX += 2; // 向右移動玩家
      playerDirection = 1; // 面向右
    } else {
      bgX += scrollSpeed; // 向右移動背景
      enemySpeed = reducedEnemySpeed; // 降低敵人速度
    }
    moved = true;
  } else if (joystickX > 2500) {
    if (playerX > 110) { // 恢復原範圍
      playerX -= 2; // 向左移動玩家
      playerDirection = -1; // 面向左
    } else {
      bgX -= scrollSpeed; // 向左移動背景
      enemySpeed = reducedEnemySpeed; // 降低敵人速度
    }
    moved = true;
  } else {
    enemySpeed = 0.05; // 恢復正常敵人速度
  }

  int jumpButtonState = digitalRead(JUMP_BTN);
  if (jumpButtonState != lastJumpButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (jumpButtonState == LOW && !isJumping && !jumpButtonPressed) {
      isJumping = true;
      currentVelocity = jumpVelocity;
      jumpButtonPressed = true;
      moved = true;
    } else if (jumpButtonState == HIGH) {
      jumpButtonPressed = false;
    }
  }

  lastJumpButtonState = jumpButtonState;

  int attackButtonState = digitalRead(ATTACK_BTN);
  if (attackButtonState != lastAttackButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (attackButtonState == LOW && !attackButtonPressed) {
      shootBullet();
      attackButtonPressed = true;
      moved = true;
    } else if (attackButtonState == HIGH) {
      attackButtonPressed = false;
    }
  }

  lastAttackButtonState = attackButtonState;

  // 檢查是否持續朝一個方向移動
  if (moved) {
    unsigned long currentTime = millis();
    if ((playerDirection == 1 && joystickX < 1500) || (playerDirection == -1 && joystickX > 2500)) {
      sameDirectionDuration = currentTime - lastDirectionChangeTime;
      if (sameDirectionDuration > directionThreshold) {
        enemySpeed = reducedEnemySpeed;
        enemySlowed = true; // 设置敌人变慢标志
      } else {
        enemySpeed = 0.05;
        enemySlowed = false; // 重置敌人变慢标志
      }
    } else {
      sameDirectionDuration = 0;
      lastDirectionChangeTime = currentTime;
      enemySlowed = false; // 重置敌人变慢标志
    }
  }
}

bool debounceButton(int pin, bool& lastButtonState, void (*callback)()) {
  bool currentButtonState = digitalRead(pin);
  if (currentButtonState != lastButtonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (currentButtonState == LOW && lastButtonState == HIGH) {
      callback();
    }
  }
  lastButtonState = currentButtonState;
  return currentButtonState == LOW;
}

void shootBullet() {
  for (int i = 0; i < maxBullets; i++) {
    if (!bullets[i].isActive) {
      bullets[i].x = playerX + (playerDirection == 1 ? playerWidth : -bulletWidth);
      bullets[i].y = playerY + playerHeight / 2 - bulletHeight / 2;
      bullets[i].lastX = bullets[i].x;
      bullets[i].lastY = bullets[i].y;
      bullets[i].isActive = true;
      bullets[i].direction = playerDirection;
      break;
    }
  }
}

void updatePhysics() {
  if (isJumping) {
    lastPlayerY = playerY; // 更新前儲存之前的Y
    playerY += currentVelocity;
    currentVelocity += gravity;

    // 檢查是否與平台碰撞
    for (int i = 0; i < numPlatforms; i++) {
      int platformLeft = platformX[i] - bgX;
      int platformRight = platformLeft + platformWidth[i];
      int platformTop = platformY[i];
      int platformBottom = platformTop + platformHeight;

      // 檢查玩家是否落在平台上
      if (playerX + playerWidth > platformLeft && playerX < platformRight &&
          lastPlayerY + playerHeight <= platformTop && playerY + playerHeight >= platformTop) {
        playerY = platformTop - playerHeight;
        isJumping = false;
        currentVelocity = 0;
      }
    }

    if (playerY >= groundY - playerHeight) {
      playerY = groundY - playerHeight;
      isJumping = false;
    }
  } else {
    // 確保在角色不跳躍時仍然檢測平台碰撞
    bool onPlatform = false;
    for (int i = 0; i < numPlatforms; i++) {
      int platformLeft = platformX[i] - bgX;
      int platformRight = platformLeft + platformWidth[i];
      int platformTop = platformY[i];
      int platformBottom = platformTop + platformHeight;

      if (playerX + playerWidth > platformLeft && playerX < platformRight &&
          playerY + playerHeight >= platformTop && playerY + playerHeight <= platformBottom) {
        playerY = platformTop - playerHeight;
        onPlatform = true;
        break;
      }
    }
    if (!onPlatform && playerY < groundY - playerHeight) {
      isJumping = true;
      currentVelocity = 0;
    } else if (!onPlatform && playerY >= groundY - playerHeight) {
      playerY = groundY - playerHeight;
    }

    // 更新敵人追擊玩家
    if (abs(playerX - enemyX) < tft.width() / 2) {
      enemySpeed = 0.1;
    } else {
      enemySpeed = 0.05;
    }

    // 檢查敵人是否撞擊玩家
    unsigned long currentTime = millis();
    if (playerX + playerWidth > enemyX && playerX < enemyX + enemyWidth &&
        playerY + playerHeight > enemyY && playerY < enemyY + enemyHeight) {
      if (currentTime - lastDamageTime > damageInterval) {
        playerHealth -= random(0, 16); // 隨機減少0到15之間
        lastDamageTime = currentTime;
        if (playerHealth <= 0) {
          playerHealth = 0;
          drawGameOverScreen();
          waitForRestartButton();
          return;
        }
      }
    }
  }

  // 更新敵人位置以跟隨玩家,使用平滑運動效果
  enemyX += (playerX - enemyX) * enemySpeed;

  // 更新敵人Y位置,使用平滑運動效果
  if (enemyIsJumping) {
    enemyY += enemyCurrentVelocity;
    enemyCurrentVelocity += gravity;
    if (enemyY >= groundY - enemyHeight) {
      enemyY = groundY - enemyHeight;
      enemyIsJumping = false;
    }
  } else {
    bool enemyOnPlatform = false;
    for (int i = 0; i < numPlatforms; i++) {
      int platformLeft = platformX[i] - bgX;
      int platformRight = platformLeft + platformWidth[i];
      int platformTop = platformY[i];
      int platformBottom = platformTop + platformHeight;

      if (enemyX + enemyWidth > platformLeft && enemyX < platformRight &&
          enemyY + enemyHeight >= platformTop && enemyY + enemyHeight <= platformBottom) {
        enemyY = platformTop - enemyHeight;
        enemyOnPlatform = true;
        break;
      }
    }
    if (!enemyOnPlatform && enemyY < groundY - enemyHeight) {
      enemyIsJumping = true;
      enemyCurrentVelocity = 0;
    } else if (!enemyOnPlatform && enemyY >= groundY - enemyHeight) {
      enemyY = groundY - enemyHeight;
    }
  }

  // 如果玩家跳躍則觸發敵人跳躍
  if (isJumping && !enemyIsJumping) {
    enemyIsJumping = true;
    enemyCurrentVelocity = jumpVelocity;
  }
}

bool checkBulletCollision(int bulletX, int bulletY) {
  // 檢查子彈是否與平台或地面碰撞
  if (bulletY >= groundY || bulletX <= 0 || bulletX >= tft.width()) {
    return true;
  }

  for (int i = 0; i < numPlatforms; i++) {
    int platformLeft = platformX[i] - bgX;
    int platformRight = platformLeft + platformWidth[i];
    int platformTop = platformY[i];
    int platformBottom = platformTop + platformHeight;

    if (bulletX + bulletWidth > platformLeft && bulletX < platformRight &&
        bulletY + bulletHeight > platformTop && bulletY < platformBottom) {
      return true;
    }
  }
  return false;
}

void updateBullets() {
  for (int i = 0; i < maxBullets; i++) {
    if (bullets[i].isActive) {
      // 清除之前的子彈位置
      tft.fillRect(bullets[i].lastX, bullets[i].lastY, bulletWidth, bulletHeight, ILI9341_BLACK);

      // 更新子彈位置
      bullets[i].lastX = bullets[i].x;
      bullets[i].lastY = bullets[i].y;
      bullets[i].x += bulletSpeed * bullets[i].direction;

      // 檢查子彈是否碰撞牆壁、平台或超出屏幕
      if (checkBulletCollision(bullets[i].x, bullets[i].y)) {
        bullets[i].isActive = false;
      } else {
        // 檢查是否與敵人碰撞
        if (bullets[i].x + bulletWidth > enemyX && bullets[i].x < enemyX + enemyWidth &&
            bullets[i].y + bulletHeight > enemyY && bullets[i].y < enemyY + enemyHeight) {
          bullets[i].isActive = false;
          if (enemyHealth > 0) {
            enemyHealth--;
          }
          if (enemyHealth == 0) {
            enemyX = tft.width() + enemyWidth; // 將敵人移到屏幕右邊
            enemyHealth = 3; // 重置敵人血量
          }
        }
      }
    }
  }
}

void redrawGraphics() {
  drawImage();
  drawPlatforms();  // 確保平台隨角色和背景重繪
  drawCharacter();
  drawEnemy();
  drawBullets();
  drawHealthBar();
}

void drawCharacter() {
  // 僅清除角色的上一個區域以避免畫在角色上
  tft.fillRect(lastPlayerX, lastPlayerY, playerWidth, playerHeight, ILI9341_BLACK);
  tft.fillRect(playerX, playerY, playerWidth, playerHeight, ILI9341_WHITE);
  lastPlayerX = playerX;
  lastPlayerY = playerY;
}

void drawTerrain() {
  // 畫一條簡單的水平線作為地形
  tft.drawFastHLine(0, groundY, tft.width(), ILI9341_WHITE); // 畫白色地形線
}

void drawImage() {
  int x = -bgX;
  int drawX = (x % tft.width());
  tft.drawRGBBitmap(144 + x, 96, mlimage, 16, 16);
}

void drawPlatforms() {
  int platformWidth = 60;  // 統一平台寬度
  int platformHeight = 10; // 統一平台高度

  // 預定的固定高度
  for (int i = 0; i < numPlatforms; i++) {
    // 清除之前的平台位置
    tft.fillRect(lastPlatformX[i], platformY[i], platformWidth, platformHeight, ILI9341_BLACK);

    // 根據背景滾動計算當前平台位置
    lastPlatformX[i] = platformX[i] - bgX;

    tft.fillRect(lastPlatformX[i], platformY[i], platformWidth, platformHeight, ILI9341_YELLOW);
  }
}

void drawEnemy() {
  // 僅清除敵人的上一個區域以避免畫在敵人上
  static int lastEnemyX = enemyX;
  static int lastEnemyY = enemyY;
  tft.fillRect(lastEnemyX, lastEnemyY, enemyWidth, enemyHeight, ILI9341_BLACK);
  if (enemyHealth > 0) {
    tft.fillRect(enemyX, enemyY, enemyWidth, enemyHeight, ILI9341_RED);
  }
  lastEnemyX = enemyX;
  lastEnemyY = enemyY;
}

void drawBullets() {
  for (int i = 0; i < maxBullets; i++) {
    if (bullets[i].isActive) {
      tft.fillRect(bullets[i].x, bullets[i].y, bulletWidth, bulletHeight, ILI9341_GREEN);
    }
  }
}

void drawHealthBar() {
  int healthBarWidth = map(playerHealth, 0, 100, 0, tft.width() - 20);
  tft.fillRect(10, 10, tft.width() - 20, 10, ILI9341_BLACK); // 清除之前的血條
  tft.fillRect(10, 10, healthBarWidth, 10, ILI9341_GREEN);  // 畫新的血條
  tft.fillRect(10, 25, 120, 20, ILI9341_BLACK); // 清除之前的血量數字
  tft.setCursor(10, 25);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(2);
  tft.print("Blood: ");
  tft.print(playerHealth);
  tft.print("/100");
}

void drawGameOverScreen() {
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_RED);
  tft.setTextSize(4);
  tft.setCursor(30, tft.height() / 2 - 15);
  tft.println("GAME OVER");
  tft.setTextSize(1.7);
  tft.setCursor(30, tft.height() / 2 + 20); // 調整游標位置
  tft.println("Push the yellow button to restart");
}

void restartGame() {
  a = 1;
  tft.fillScreen(ILI9341_BLACK);
}