/* ================================================================
 *  Connect Four — Pico 2W + PicoResTouch-LCD-2.8
 *  Main entry: setup, loop, state dispatch
 * ================================================================ */

#include <Arduino.h>
#include <SPI.h>
#include <EEPROM.h>
#include "config.h"
#include "game.h"
#include "touch.h"
#include "storage.h"
#include "display.h"

// --- State handlers ---

void startGame(int mode)
{
    resetBoard();
    gameMenuMode = mode;
    gameLevel = currentLookAhead;
    currentPlayer = 1;
    activeCol = 3;
    currentMoves = "";
    gameState = (mode == 1) ? AI_TURN : PLAYING;
    lastActivityTime = millis();
    needRedraw = true;
}

void returnToMenu()
{
    abortAi = true;
    resetBoard();
    gameState = MENU;
    menuMode = 0;
    lastActivityTime = millis();
    needRedraw = true;
}

void startDemo()
{
    resetBoard();
    randomizeDemoPlies();
    gameState = DEMO;
    currentPlayer = 1;
    lastActivityTime = millis();
    lastDemoMove = millis();
    needRedraw = true;
}

void handleAiTurn()
{
    int8_t aiP = (gameMenuMode == 0) ? 2 : 1;
    int bestCol = computeAiMove(aiP);
    if (abortAi)
    {
        returnToMenu();
        return;
    }

    delay(150);
    animateDrop(bestCol, aiP);
    activeCol = bestCol;

    if (!checkGameEnd())
    {
        gameState = PLAYING;
        currentPlayer = (aiP == 1) ? 2 : 1;
        drawGameStatus();
    }
    else
    {
        drawBoardFull();
        drawGameStatus();
    }
    lastActivityTime = millis();
}

void handleDemoStep()
{
    if (millis() - lastDemoMove < 400)
        return;
    lastDemoMove = millis();

    int bestCol = computeAiMove(currentPlayer);
    if (abortAi)
    {
        returnToMenu();
        return;
    }

    animateDrop(bestCol, currentPlayer);

    if (!checkGameEnd())
    {
        currentPlayer = (currentPlayer == 1) ? 2 : 1;
    }
    else
    {
        drawBoardFull();
        drawGameStatus();
    }
}

void handleFlash()
{
    if (millis() - lastFlash > 400)
    {
        lastFlash = millis();
        flashToggle = !flashToggle;
        for (int c = 0; c < COLS; c++)
            for (int r = 0; r < ROWS; r++)
                if (board[c][r] != 0)
                    drawCell(c, r);
    }
    if (millis() - demoResetTimer > DEMO_RESET_PAUSE)
        startDemo();
}

// --- Setup ---

void setup()
{
    Serial.begin(115200);

    analogWrite(LCD_BL, 255);

    SPI1.setRX(12);
    SPI1.setTX(11);
    SPI1.setSCK(10);

    pinMode(TCH_CS, OUTPUT);
    digitalWrite(TCH_CS, HIGH);

    tft.init(240, 320);
    tft.setRotation(0);
    tft.fillScreen(C_BG);

    initStorage();

    bool needCal = (EEPROM.read(EEPROM_CAL) != CAL_MAGIC);
    if (!needCal)
    {
        delay(100);
        int16_t rx, ry;
        if (readRawTouch(rx, ry))
        {
            tft.fillScreen(ST77XX_BLACK);
            tft.setTextSize(2);
            tft.setTextColor(ST77XX_WHITE);
            tft.setCursor(10, 140);
            tft.print("Recalibrating...");
            while (readRawTouch(rx, ry))
                delay(50);
            needCal = true;
        }
    }
    if (needCal)
        calibrateTouch();
    loadCalibration();

    loadSettings();
    loadGameLog();

    randomSeed(analogRead(26));
    lastActivityTime = millis();
    needRedraw = true;
}

// --- Loop ---

void loop()
{
    uint16_t tx, ty;
    bool touchDown = getTouchDown(tx, ty);

    if (touchDown)
    {
        lastActivityTime = millis();

        switch (gameState)
        {
        case MENU:
        {
            int item = menuItemFromTouch(tx, ty);
            if (item >= 0 && item < 3)
                startGame(item);
            else if (item == 3)
            {
                gameState = SETTINGS;
                needRedraw = true;
            }
            break;
        }
        case PLAYING:
        {
            int col = colFromTouch(tx, ty);
            if (col >= 0)
            {
                int row = getFirstEmptyRow(col);
                if (row >= 0)
                {
                    animateDrop(col, currentPlayer);
                    if (!checkGameEnd())
                    {
                        if (gameMenuMode < 2)
                        {
                            gameState = AI_TURN;
                            drawGameStatus();
                        }
                        else
                        {
                            currentPlayer = (currentPlayer == 1) ? 2 : 1;
                            drawGameStatus();
                        }
                    }
                    else
                    {
                        drawBoardFull();
                        drawGameStatus();
                    }
                }
            }
            break;
        }
        case SETTINGS:
        {
            int result = handleSettingsTouch(tx, ty);
            if (result == 1)
            {
                gameState = MENU;
                needRedraw = true;
            }
            else if (result == 2)
            {
                gameState = GAME_LOG;
                needRedraw = true;
            }
            else if (result == 3)
            {
                calibrateTouch();
                gameState = SETTINGS;
                needRedraw = true;
            }
            break;
        }
        case GAME_LOG:
        {
            int result = handleGameLogTouch(tx, ty);
            if (result == 1)
            {
                gameState = SETTINGS;
                needRedraw = true;
            }
            break;
        }
        case FINISHED_WIN:
        case FINISHED_DRAW:
        case DEMO:
            returnToMenu();
            break;
        default:
            break;
        }
    }

    if (needRedraw)
    {
        needRedraw = false;
        switch (gameState)
        {
        case MENU:
            drawMenu();
            break;
        case SETTINGS:
            drawSettings();
            break;
        case GAME_LOG:
            drawGameLogScreen();
            break;
        default:
            drawGameScreen();
            break;
        }
    }

    if (gameState == AI_TURN)
        handleAiTurn();
    if (gameState == DEMO)
        handleDemoStep();
    if (gameState == FINISHED_WIN || gameState == FINISHED_DRAW)
        handleFlash();

    if (gameState == PLAYING || gameState == MENU)
    {
        if (millis() - lastActivityTime > (uint32_t)DEFAULT_IDLE_TIMEOUT * 1000)
            startDemo();
    }
}
