#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <pgmspace.h>

// TFT display connections
#define TFT_CS    D0
#define TFT_RST   D2
#define TFT_DC    D1

// Button connections
#define BUTTON_LEFT   A3
#define BUTTON_RIGHT  A4
#define BUTTON_SHOOT  A5

// Define threshold for touch sensitivity
#define TOUCH_THRESHOLD 30

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

struct Object {
  int16_t x, y;
  uint16_t color;
  bool active;
};

struct Projectile {
  int16_t x, y;
  bool active;
};

struct Explosion {
  int16_t x, y;
  uint8_t frame;
  bool active;
};

Object enemies[15];
Projectile bullets[10];
Projectile enemyBullets[10];
Explosion explosions[5];
int16_t paddleX = 130; // Initial paddle position (shifted right)
int score = 0;
int lives = 3;
int level = 1;
bool gameOver = false;
uint8_t direction = 0; // 0 for right, 1 for left

void setupEnemies() {
  for (int i = 0; i < 15; i++) {
    uint16_t color;
    if (i < 5) {
      color = ILI9341_RED;
    } else if (i < 10) {
      color = ILI9341_GREEN;
    } else {
      color = ILI9341_BLUE;
    }
    enemies[i] = { random(30, 190), random(-320, 0), color, true }; // Shifted right
  }
}

void moveEnemies() {
  for (int i = 0; i < 15; i++) {
    if (enemies[i].active) {
      enemies[i].y += (i % 3 == 0) ? 1 : 2; // Different speeds for different enemies
      if (enemies[i].y > 320) {
        enemies[i].y = random(-320, 0);
        enemies[i].x = random(30, 190); // Shifted right
      }

      if (random(0, 100) < 3) {
        for (int j = 0; j < 10; j++) {
          if (!enemyBullets[j].active) {
            enemyBullets[j] = { enemies[i].x + 5, enemies[i].y + 10, true };
            break;
          }
        }
      }
    }
  }
}

void drawEnemies() {
  for (int i = 0; i < 15; i++) {
    if (enemies[i].active) {
      tft.fillRect(enemies[i].x, enemies[i].y, 10, 10, enemies[i].color);
    }
  }
}

void moveBullets() {
  for (int i = 0; i < 10; i++) {
    if (bullets[i].active) {
      bullets[i].y -= 5;
      if (bullets[i].y < 0) {
        bullets[i].active = false;
      }
      for (int j = 0; j < 15; j++) {
        if (enemies[j].active && bullets[i].x > enemies[j].x && bullets[i].x < enemies[j].x + 10 && bullets[i].y > enemies[j].y && bullets[i].y < enemies[j].y + 10) {
          bullets[i].active = false;
          enemies[j].active = false;
          score += 10;
          // Trigger explosion
          for (int k = 0; k < 5; k++) {
            if (!explosions[k].active) {
              explosions[k] = { enemies[j].x + 5, enemies[j].y + 5, 0, true };
              break;
            }
          }
          if (score % 150 == 0) {
            level++;
          }
        }
      }
    }
    if (enemyBullets[i].active) {
      enemyBullets[i].y += 3;
      if (enemyBullets[i].y > 320) {
        enemyBullets[i].active = false;
      }
      if (enemyBullets[i].x > paddleX && enemyBullets[i].x < paddleX + 20 && enemyBullets[i].y > 240 && enemyBullets[i].y < 250) {
        enemyBullets[i].active = false;
        lives--;
        if (lives <= 0) {
          gameOver = true;
        }
      }
    }
  }
}

void drawBullets() {
  for (int i = 0; i < 10; i++) {
    if (bullets[i].active) {
      tft.fillRect(bullets[i].x, bullets[i].y, 2, 5, ILI9341_WHITE);
    }
    if (enemyBullets[i].active) {
      tft.fillRect(enemyBullets[i].x, enemyBullets[i].y, 2, 5, ILI9341_YELLOW);
    }
  }
}

// Adjusted Background Drawing to use the entire screen
void drawBackground() {
  tft.fillScreen(ILI9341_BLACK);
  for (int y = 0; y < 320; y += 20) {
    for (int x = 20; x < 240; x += 20) { // Shifted right
      if (random(0, 10) < 2) {
        tft.drawPixel(x + random(0, 20), y + random(0, 20), ILI9341_WHITE);
      }
    }
  }
}

// Adjusted UI Panel Positioning to use the full screen width
void drawUI() {
  tft.fillRect(210, 0, 30, 320, ILI9341_DARKGREY);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(1);
  tft.setCursor(215, 10);
  tft.print("Lives:");
  for (int i = 0; i < lives; i++) {
    tft.fillRect(215, 20 + i * 10, 10, 10, ILI9341_RED);
  }
  tft.setCursor(215, 70);
  tft.print("Score:");
  tft.setCursor(215, 80);
  tft.print(score);
  tft.setCursor(215, 100);
  tft.print("Level:");
  tft.setCursor(215, 110);
  tft.print(level);
}

void drawExplosions() {
  for (int i = 0; i < 5; i++) {
    if (explosions[i].active) {
      int16_t x = explosions[i].x;
      int16_t y = explosions[i].y;
      uint8_t frame = explosions[i].frame;
      uint16_t color = (frame % 2 == 0) ? ILI9341_YELLOW : ILI9341_RED;
      tft.drawCircle(x, y, frame * 2, color);
      explosions[i].frame++;
      if (explosions[i].frame > 5) {
        explosions[i].active = false;
      }
    }
  }
}

// Adjusted Spaceship Position to be higher up
void drawSpaceship(int16_t x, int16_t y) {
  tft.fillTriangle(x, y, x + 15, y + 25, x - 15, y + 25, ILI9341_WHITE); // Wider spaceship
}

void setup() {
  tft.begin();
  tft.setRotation(1);
  drawBackground();
  setupEnemies();
  
  pinMode(BUTTON_LEFT, INPUT);
  pinMode(BUTTON_RIGHT, INPUT);
  pinMode(BUTTON_SHOOT, INPUT);
}

void loop() {
  if (!gameOver) {
    drawBackground();
    drawEnemies();
    drawBullets();
    drawExplosions();
    drawSpaceship(paddleX + 15, 230); // Draw spaceship higher up
    drawUI();

    moveEnemies();
    moveBullets();

    
    // Read touch states and compare with threshold
    if (touchRead(BUTTON_LEFT) < TOUCH_THRESHOLD) {
      paddleX -= 2;
      if (paddleX <= 30) paddleX = 30;
    }
    if (touchRead(BUTTON_RIGHT) < TOUCH_THRESHOLD) {
      paddleX += 2;
      if (paddleX >= 190) paddleX = 190;
    }
    if (touchRead(BUTTON_SHOOT) < TOUCH_THRESHOLD) {
      for (int i = 0; i < 10; i++) {
        if (!bullets[i].active) {
          bullets[i] = {paddleX + 15, 220, true};
          break;
        }
      }
    }

    delay(50);
  } else {
    tft.fillScreen(ILI9341_BLACK);
    tft.setCursor(50, 140);
    tft.setTextColor(ILI9341_RED);
    tft.setTextSize(2);
    tft.print("Game Over!");
    tft.setCursor(50, 180);
    tft.setTextColor(ILI9341_WHITE);
    tft.setTextSize(2);
    tft.print("Score: ");
    tft.print(score);
  }
}