#include "display.h"
#include "config.h"
#include "game.h"
#include "storage.h"

// --- Text helpers ---

void drawTextCenter(int16_t cx, int16_t cy, const char *text,
                    uint16_t fg, uint8_t size)
{
    tft.setTextSize(size);
    tft.setTextColor(fg);
    int16_t bx, by;
    uint16_t bw, bh;
    tft.getTextBounds(text, 0, 0, &bx, &by, &bw, &bh);
    tft.setCursor(cx - bw / 2 - bx, cy - bh / 2 - by);
    tft.print(text);
}

static void drawButton(int16_t x, int16_t y, int16_t w, int16_t h,
                       const char *label, uint16_t fg, uint16_t bg)
{
    tft.fillRoundRect(x, y, w, h, 6, bg);
    tft.drawRoundRect(x, y, w, h, 6, fg);
    drawTextCenter(x + w / 2, y + h / 2, label, fg, 2);
}

// --- Game board ---

void drawCell(int c, int r)
{
    int cx = cellX(c), cy = cellY(r);
    int8_t v = board[c][r];

    if (v == 0)
    {
        tft.fillCircle(cx, cy, DISC_R, C_EMPTY);
        return;
    }
    if (gameState == FINISHED_WIN)
    {
        if (isWinPos(c, r))
            tft.fillCircle(cx, cy, DISC_R, flashToggle ? C_EMPTY : playerColor(v));
        else
            tft.fillCircle(cx, cy, DISC_R, playerColorDim(v));
    }
    else if (gameState == FINISHED_DRAW)
    {
        tft.fillCircle(cx, cy, DISC_R, flashToggle ? C_EMPTY : playerColor(v));
    }
    else
    {
        tft.fillCircle(cx, cy, DISC_R, playerColor(v));
    }
}

void drawBoardFull()
{
    tft.fillRoundRect(BRD_X - 4, BRD_Y - 4,
                      COLS * CELL + 8, ROWS * CELL + 8, 6, C_BOARD);
    for (int c = 1; c < COLS; c++)
        tft.drawFastVLine(BRD_X + c * CELL, BRD_Y, ROWS * CELL, C_GRID);
    for (int r = 1; r < ROWS; r++)
        tft.drawFastHLine(BRD_X, BRD_Y + r * CELL, COLS * CELL, C_GRID);
    for (int c = 0; c < COLS; c++)
        for (int r = 0; r < ROWS; r++)
            drawCell(c, r);
}

void drawColNumbers()
{
    tft.setTextSize(1);
    tft.setTextColor(C_TXTDIM, C_BG);
    for (int c = 0; c < COLS; c++)
    {
        tft.setCursor(cellX(c) - 3, BRD_Y - 12);
        tft.print(c + 1);
    }
}

void drawStatus(const char *text, uint16_t color)
{
    tft.fillRect(0, STAT_Y - 2, 240, 20, C_BG);
    drawTextCenter(120, STAT_Y + 7, text, color, 2);
}

void drawSubStatus(const char *text)
{
    tft.fillRect(0, SSTAT_Y - 2, 240, 16, C_BG);
    drawTextCenter(120, SSTAT_Y + 5, text, C_TXTDIM, 1);
}

void drawGameStatus()
{
    if (gameState == PLAYING)
    {
        if (gameMenuMode == 2)
        {
            drawStatus(currentPlayer == 1 ? "Yellow's turn" : "Red's turn",
                       playerColor(currentPlayer));
        }
        else
        {
            int humanP = (gameMenuMode == 0) ? 1 : 2;
            drawStatus(currentPlayer == humanP ? "Your turn" : "AI thinking...",
                       playerColor(currentPlayer));
        }
        drawSubStatus("");
    }
    else if (gameState == AI_TURN)
    {
        int8_t aiP = (gameMenuMode == 0) ? 2 : 1;
        drawStatus("AI thinking...", playerColor(aiP));
        drawSubStatus("");
    }
    else if (gameState == FINISHED_WIN)
    {
        drawStatus(winnerPlayer == 1 ? "Yellow wins!" : "Red wins!",
                   playerColor(winnerPlayer));
        drawSubStatus("Touch for menu");
    }
    else if (gameState == FINISHED_DRAW)
    {
        drawStatus("Draw!", C_TEXT);
        drawSubStatus("Touch for menu");
    }
    else if (gameState == DEMO)
    {
        drawStatus("Demo mode", C_TXTDIM);
        drawSubStatus("Touch for menu");
    }
}

void drawGameScreen()
{
    tft.fillScreen(C_BG);
    drawBoardFull();
    drawColNumbers();
    drawGameStatus();
}

// --- Menu ---

void drawMenu()
{
    tft.fillScreen(C_BG);

    tft.setTextSize(3);
    tft.setTextColor(C_P1);
    tft.setCursor(18, 18);
    tft.print("Connect");
    tft.setTextColor(C_P2);
    tft.setCursor(148, 18);
    tft.print("Four");

    const char *labels[] = {"Play as Yellow", "Play as Red", "Two Players", "Settings"};
    uint16_t colors[] = {C_P1, C_P2, C_MULTI, C_TXTDIM};
    int itemW = 220, itemH = 36, mx = 10, startY = 80, gap = 6;

    for (int i = 0; i < 4; i++)
    {
        int iy = startY + i * (itemH + gap);
        bool sel = (i == menuMode);

        if (sel)
        {
            tft.fillRoundRect(mx, iy, itemW, itemH, 6, C_MENUSEL);
            tft.drawRoundRect(mx, iy, itemW, itemH, 6, colors[i]);
        }
        else
        {
            tft.fillRoundRect(mx, iy, itemW, itemH, 6, C_BG);
        }

        tft.setTextSize(2);
        tft.setTextColor(sel ? colors[i] : C_TXTDIM);
        int16_t bx, by;
        uint16_t bw, bh;
        tft.getTextBounds(labels[i], 0, 0, &bx, &by, &bw, &bh);
        tft.setCursor(mx + (itemW - bw) / 2 - bx, iy + (itemH - bh) / 2 - by);
        tft.print(labels[i]);
    }

    drawTextCenter(120, startY + 4 * (itemH + gap) + 8,
                   "Touch to select", C_TXTDIM, 1);
}

// --- Animation ---

void animateDrop(int col, int player)
{
    int targetRow = getFirstEmptyRow(col);
    if (targetRow == -1)
        return;
    if (gameState != DEMO)
        currentMoves += String(col);

    uint16_t color = playerColor(player);
    for (int r = ROWS - 1; r >= targetRow; r--)
    {
        int cx = cellX(col), cy = cellY(r);
        tft.fillCircle(cx, cy, DISC_R, color);
        delay(max(10, 60 - (ROWS - 1 - r) * 10));
        if (r > targetRow)
            tft.fillCircle(cx, cy, DISC_R, C_EMPTY);
    }
    board[col][targetRow] = player;
}

// ================================================================
//  Settings screen
// ================================================================

static void drawSettingsValue(int y, const char *label, const char *value)
{
    tft.fillRect(0, y, 240, 32, C_BG);
    tft.setTextSize(2);
    tft.setTextColor(C_TEXT);
    tft.setCursor(10, y + 8);
    tft.print(label);

    // [-] button
    tft.fillRoundRect(140, y, 30, 28, 4, C_MENUSEL);
    tft.drawRoundRect(140, y, 30, 28, 4, C_TXTDIM);
    drawTextCenter(155, y + 14, "-", C_TEXT, 2);

    // Value
    tft.fillRect(174, y, 36, 28, C_BG);
    drawTextCenter(192, y + 14, value, C_P1, 2);

    // [+] button
    tft.fillRoundRect(214, y, 30, 28, 4, C_MENUSEL);
    tft.drawRoundRect(214, y, 30, 28, 4, C_TXTDIM);
    drawTextCenter(229, y + 14, "+", C_TEXT, 2);
}

static void drawSettingsToggle(int y, const char *label, bool on)
{
    tft.fillRect(0, y, 240, 32, C_BG);
    tft.setTextSize(2);
    tft.setTextColor(C_TEXT);
    tft.setCursor(10, y + 8);
    tft.print(label);

    uint16_t col = on ? C565(40, 167, 69) : C565(120, 50, 50);
    tft.fillRoundRect(150, y, 70, 28, 4, col);
    tft.drawRoundRect(150, y, 70, 28, 4, C_TXTDIM);
    drawTextCenter(185, y + 14, on ? "ON" : "OFF", C_TEXT, 2);
}

void drawSettings()
{
    tft.fillScreen(C_BG);

    tft.setTextSize(2);
    tft.setTextColor(C_TEXT);
    tft.setCursor(70, 10);
    tft.print("Settings");
    tft.drawFastHLine(10, 34, 220, C_GRID);

    char buf[8];
    snprintf(buf, sizeof(buf), "%d", currentLookAhead);
    drawSettingsValue(50, "AI Ply:", buf);

    drawSettingsToggle(90, "Blunder:", blunderEnabled);

    snprintf(buf, sizeof(buf), "%d%%", blunderChance);
    drawSettingsValue(130, "Bl. Pct:", buf);

    drawButton(10, 180, 220, 34, "View Game Log", C_MULTI, C_MENUSEL);
    drawButton(10, 222, 220, 34, "Recalibrate", C_TXTDIM, C_MENUSEL);
    drawButton(10, 274, 220, 34, "Back", C_TEXT, C_MENUSEL);
}

int handleSettingsTouch(uint16_t x, uint16_t y)
{
    // AI Ply +/-
    if (y >= 50 && y < 82)
    {
        if (x >= 140 && x < 170)
        {
            if (currentLookAhead > 1)
                currentLookAhead--;
            drawSettings();
        }
        if (x >= 214 && x < 244)
        {
            if (currentLookAhead < 10)
                currentLookAhead++;
            drawSettings();
        }
        return 0;
    }
    // Blunder toggle
    if (y >= 90 && y < 122 && x >= 150 && x < 220)
    {
        blunderEnabled = !blunderEnabled;
        drawSettings();
        return 0;
    }
    // Blunder % +/-
    if (y >= 130 && y < 162)
    {
        if (x >= 140 && x < 170)
        {
            if (blunderChance > 5)
                blunderChance -= 5;
            drawSettings();
        }
        if (x >= 214 && x < 244)
        {
            if (blunderChance < 100)
                blunderChance += 5;
            drawSettings();
        }
        return 0;
    }
    // View Game Log
    if (y >= 180 && y < 214 && x >= 10 && x <= 230)
        return 2;
    // Recalibrate
    if (y >= 222 && y < 256 && x >= 10 && x <= 230)
        return 3;
    // Back
    if (y >= 274 && y < 308 && x >= 10 && x <= 230)
    {
        saveSettings();
        return 1;
    }
    return 0;
}

// ================================================================
//  Game log screen
// ================================================================

static int logPage = 0;
static const int LOG_PER_PAGE = 12;
static bool confirmClear = false;

void drawGameLogScreen()
{
    tft.fillScreen(C_BG);
    confirmClear = false;

    // Title
    tft.setTextSize(2);
    tft.setTextColor(C_TEXT);
    tft.setCursor(10, 6);
    tft.print("Game Log (");
    tft.print(gameLogCount);
    tft.print(")");
    tft.drawFastHLine(10, 28, 220, C_GRID);

    if (gameLogCount == 0)
    {
        drawTextCenter(120, 150, "No games yet", C_TXTDIM, 2);
    }
    else
    {
        // Header
        tft.setTextSize(1);
        tft.setTextColor(C_TXTDIM);
        tft.setCursor(6, 34);
        tft.print(" #  Typ Lv Win Moves");

        // Entries (newest first)
        int totalPages = (gameLogCount + LOG_PER_PAGE - 1) / LOG_PER_PAGE;
        if (logPage >= totalPages)
            logPage = totalPages - 1;
        if (logPage < 0)
            logPage = 0;

        int startIdx = gameLogCount - 1 - logPage * LOG_PER_PAGE;

        for (int row = 0; row < LOG_PER_PAGE && startIdx - row >= 0; row++)
        {
            int idx = startIdx - row;
            int ry = 48 + row * 18;
            bool playerWon = gameLog[idx].type != '2' &&
                             gameLog[idx].type == gameLog[idx].winner;

            tft.setTextSize(1);
            tft.setTextColor(playerWon ? C_P2 : C_TEXT);
            tft.setCursor(6, ry);

            char line[40];
            snprintf(line, sizeof(line), "%3d  %c  %2d  %c   %s",
                     idx + 1, gameLog[idx].type, gameLog[idx].level,
                     gameLog[idx].winner,
                     gameLog[idx].moves.substring(0, 18).c_str());
            tft.print(line);
        }

        // Page indicator
        tft.setTextSize(1);
        tft.setTextColor(C_TXTDIM);
        char pgBuf[16];
        snprintf(pgBuf, sizeof(pgBuf), "Page %d/%d", logPage + 1, totalPages);
        drawTextCenter(120, 275, pgBuf, C_TXTDIM, 1);
    }

    // Bottom buttons
    int btnY = 286;
    if (gameLogCount > LOG_PER_PAGE)
        drawButton(10, btnY, 60, 28, "Prev", C_TXTDIM, C_MENUSEL);
    drawButton(90, btnY, 60, 28, "Clear", C_P2, C_MENUSEL);
    if (gameLogCount > LOG_PER_PAGE)
        drawButton(170, btnY, 60, 28, "Next", C_TXTDIM, C_MENUSEL);

    drawButton(60, 318 - 30, 120, 28, "Back", C_TEXT, C_MENUSEL);
}

int handleGameLogTouch(uint16_t x, uint16_t y)
{
    int btnY = 286;

    if (confirmClear)
    {
        // Confirmation row
        if (y >= 150 && y < 186)
        {
            if (x >= 40 && x < 110)
            {
                clearGameLog();
                confirmClear = false;
                drawGameLogScreen();
            }
            if (x >= 130 && x < 200)
            {
                confirmClear = false;
                drawGameLogScreen();
            }
        }
        return 0;
    }

    // Prev
    if (y >= btnY && y < btnY + 28 && x >= 10 && x < 70)
    {
        if (logPage > 0)
        {
            logPage--;
            drawGameLogScreen();
        }
        return 0;
    }
    // Clear
    if (y >= btnY && y < btnY + 28 && x >= 90 && x < 150)
    {
        confirmClear = true;
        tft.fillRect(20, 140, 200, 50, C_BG);
        tft.drawRoundRect(20, 140, 200, 50, 6, C_P2);
        drawTextCenter(120, 150, "Clear all?", C_P2, 2);
        drawButton(40, 160, 70, 24, "Yes", C_P2, C_MENUSEL);
        drawButton(130, 160, 70, 24, "No", C_TEXT, C_MENUSEL);
        return 0;
    }
    // Next
    if (y >= btnY && y < btnY + 28 && x >= 170 && x < 230)
    {
        int totalPages = (gameLogCount + LOG_PER_PAGE - 1) / LOG_PER_PAGE;
        if (logPage < totalPages - 1)
        {
            logPage++;
            drawGameLogScreen();
        }
        return 0;
    }
    // Back
    if (y >= 288 && y < 318 && x >= 60 && x < 180)
        return 1;
    return 0;
}
