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

#define TFT_CLK 13
#define TFT_MISO 12
#define TFT_MOSI 11
#define TFT_DC 5
#define TFT_CS 4
#define TFT_RST 8
#define ILI9341_BLACK 0x0000
#define ILI9341_YELLOW 0xFFE0

#define JOYSTICK_X A0
#define JOYSTICK_Y A1
#define FIRE_BUTTON 2

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

const int rows = 5;
const int cols = 6;
const int enemySpeed = 2;
int enemyDirection = 1;
unsigned long lastEnemyMove = 0;

struct Enemy {
  int x, y;
  bool active;
};

Enemy enemies[rows][cols];
const int invaderSize = 2;
const int invaderWidth = invaderSize * 8;
const int invaderHeight = invaderSize * 8;

int posX = 120;
int posY = 270;
bool playerAlive = true;

// Variables pour les missiles du joueur
const int maxMissiles = 5;
int missileX[maxMissiles];
int missileY[maxMissiles];
bool missileActive[maxMissiles];
const int missileWidth = 2;
const int missileHeight = 8;

// Variables pour les missiles ennemis
const int maxEnemyMissiles = 10;
int enemyMissileX[maxEnemyMissiles];
int enemyMissileY[maxEnemyMissiles];
bool enemyMissileActive[maxEnemyMissiles];


byte invader[8] = {
  0b01000010, 0b00100100, 0b00111100, 0b11100111,
  0b10111101, 0b10011001, 0b00100100, 0b01100110
};
byte poulpodis500[8] //monstroDanseur
{
  0b00010010,
  0b00111010,
  0b00111010,
  0b10010010,
  0b11111111,
  0b00010010,
  0b01111100,
  0b01000100
};
void setup() {
  tft.begin();
  tft.fillScreen(ILI9341_BLACK);
  pinMode(JOYSTICK_X, INPUT);
  pinMode(JOYSTICK_Y, INPUT);
  pinMode(FIRE_BUTTON, INPUT_PULLUP);
  Serial.begin(9600);

  for (int i = 0; i < maxMissiles; i++) missileActive[i] = false;
  for (int i = 0; i < maxEnemyMissiles; i++) enemyMissileActive[i] = false;

  // Initialiser les ennemis
  for (int r = 0; r < rows; r++) {
    for (int c = 0; c < cols; c++) {
      enemies[r][c].x = 10 + c * (invaderWidth + 10);
      enemies[r][c].y = 10 + r * (invaderHeight + 10);
      enemies[r][c].active = true;
      drawEnemy(enemies[r][c].x, enemies[r][c].y);
    }
  }
}

void loop() {
  if (playerAlive) {
    int xValue = analogRead(JOYSTICK_X) - 512;
    int yValue = analogRead(JOYSTICK_Y) - 512;

    int oldPosX = posX;
    int oldPosY = posY;

    // Déplacer le joueur
    if (xValue > 100) posX -= 2;
    if (xValue < -100) posX += 2;
    if (yValue > 100) posY -= 2;
    if (yValue < -100) posY += 2;

    posX = constrain(posX, 0, tft.width() - invaderWidth);
    posY = constrain(posY, 0, tft.height() - invaderHeight);

    tft.fillRect(oldPosX, oldPosY, invaderWidth, invaderHeight, ILI9341_BLACK);
    drawInvader(posX, posY);

    if (digitalRead(FIRE_BUTTON) == LOW) {
      fireMissile();
    }
  }

  if (millis() - lastEnemyMove >= 200) {
    lastEnemyMove = millis();
    moveEnemies();
  }

  updateMissiles();
  updateEnemyMissiles();
  delay(10);
}

void moveEnemies() {
  for (int r = 0; r < rows; r++) {
    for (int c = 0; c < cols; c++) {
      if (enemies[r][c].active) {
        tft.fillRect(enemies[r][c].x, enemies[r][c].y, invaderWidth, invaderHeight, ILI9341_BLACK);
        enemies[r][c].x += enemyDirection * enemySpeed;
      }
    }
  }

  if (enemies[0][0].x <= 0 || enemies[0][cols - 1].x >= tft.width() - invaderWidth) {
    enemyDirection *= -1;
    for (int r = 0; r < rows; r++) {
      for (int c = 0; c < cols; c++) {
        enemies[r][c].y += invaderHeight;
      }
    }
  }

  for (int r = 0; r < rows; r++) {
    for (int c = 0; c < cols; c++) {
      if (enemies[r][c].active) {
        drawEnemy(enemies[r][c].x, enemies[r][c].y);
        if (random(100) < 2) fireEnemyMissile(enemies[r][c].x + invaderWidth / 2, enemies[r][c].y + invaderHeight);
      }
    }
  }
}

void fireMissile() {
  for (int i = 0; i < maxMissiles; i++) {
    if (!missileActive[i]) {
      missileX[i] = posX + invaderWidth / 2 - missileWidth / 2;
      missileY[i] = posY;
      missileActive[i] = true;
      break;
    }
  }
}

void updateMissiles() {
  for (int i = 0; i < maxMissiles; i++) {
    if (missileActive[i]) {
      tft.fillRect(missileX[i], missileY[i], missileWidth, missileHeight, ILI9341_BLACK);
      missileY[i] -= 5;

      if (missileY[i] < 0) missileActive[i] = false;

      for (int r = 0; r < rows; r++) {
        for (int c = 0; c < cols; c++) {
          if (enemies[r][c].active && checkCollision(missileX[i], missileY[i], missileWidth, missileHeight, enemies[r][c].x, enemies[r][c].y, invaderWidth, invaderHeight)) {
            enemies[r][c].active = false;
            missileActive[i] = false;
            tft.fillRect(enemies[r][c].x, enemies[r][c].y, invaderWidth, invaderHeight, ILI9341_BLACK);
            break;
          }
        }
      }

      if (missileActive[i]) {
        tft.fillRect(missileX[i], missileY[i], missileWidth, missileHeight, ILI9341_YELLOW);
      }
    }
  }
}

void fireEnemyMissile(int x, int y) {
  for (int i = 0; i < maxEnemyMissiles; i++) {
    if (!enemyMissileActive[i]) {
      enemyMissileX[i] = x;
      enemyMissileY[i] = y;
      enemyMissileActive[i] = true;
      break;
    }
  }
}

void updateEnemyMissiles() {
  for (int i = 0; i < maxEnemyMissiles; i++) {
    if (enemyMissileActive[i]) {
      tft.fillRect(enemyMissileX[i], enemyMissileY[i], missileWidth, missileHeight, ILI9341_BLACK);
      enemyMissileY[i] += 3;

      if (enemyMissileY[i] > tft.height()) enemyMissileActive[i] = false;

      if (playerAlive && checkCollision(enemyMissileX[i], enemyMissileY[i], missileWidth, missileHeight, posX, posY, invaderWidth, invaderHeight)) {
        playerAlive = false;
        Serial.println("Le héros est touché !");
        tft.fillRect(posX, posY, invaderWidth, invaderHeight, ILI9341_BLACK);
        enemyMissileActive[i] = false;
      }

      if (enemyMissileActive[i]) {
        tft.fillRect(enemyMissileX[i], enemyMissileY[i], missileWidth, missileHeight, ILI9341_YELLOW);
      }
    }
  }
}

bool checkCollision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) {
  return !(x1 > x2 + w2 || x1 + w1 < x2 || y1 > y2 + h2 || y1 + h1 < y2);
}

void drawEnemy(int x, int y) {
  for (int row = 0; row < 8; row++) {
    for (int col = 0; col < 8; col++) {
      if (poulpodis500[row] & (1 << (7 - col))) {
        tft.fillRect(x + col * invaderSize, y + row * invaderSize, invaderSize, invaderSize, ILI9341_YELLOW);
      }
    }
  }
}

void drawInvader(int x, int y) {
  for (int row = 0; row < 8; row++) {
    for (int col = 0; col < 8; col++) {
      if (invader[row] & (1 << (7 - col))) {
        tft.fillRect(x + col * invaderSize, y + row * invaderSize, invaderSize, invaderSize, ILI9341_YELLOW);
      }
    }
  }
}