#include "game.hpp"
#include <iostream>
#include <string>
#include <conio.h>
#include <windows.h>
#include <chrono>
#include <ctime>
#include <thread>
#include <iomanip>
#include <fstream>
using namespace std;

// Structures
struct paddle
{
    int x;
    int width;
    string paddleChar;
};
struct ball
{
    int x;
    int y;
    int vx;
    int vy;
};
struct brick
{
    int x;
    int y;
    int width;
    bool isBroken;
    int color;
    int CTB; // Collision TO Break
};

// Globals
const int width = 81;
const int height = 30;

int FPS = 60;
int frameDelay = 1000 / FPS;

int goldenCount = 0;
int TNTCount = 0;
int HardCount = 0;
int normalCount = 0;

const int panelx = 130;
const int panely = 5;

int score = 0;
int Broken = 0;
int life = 3;

int brickCol = 10;
int brickRow = 5;
const int brickWidth = 4;
const int brickGap = 1;
int brickColors[] = {9, 10, 11, 12, 13, 14};
brick bricks[14][8];

player Player = {};
paddle Paddle;
ball Ball;

// SetUp
void HideCursor(bool visible)
{
    HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO info;
    info.dwSize = 100;
    info.bVisible = visible;
    SetConsoleCursorInfo(consoleHandle, &info);
}
void initializeBricks();
void initializePaddle(paddle &paddle, int width);
void initializeBall(ball &Ball);

// Game
void input();
void logic(ball &);
// void render();
// void renderPanel();

bool game();
int gameDelay = 150;
bool gameOver = false;
bool bricksCount();

// Pause
void render(string pause);
void pauseMenu();
int pauseOption = 1;

// Other Prototypes
void explodeBricks(int col, int row);
void nextStage();

// Game History
player history[100] = {};
int historyCount = 0;

// Load Game
player loadedPlayer[100] = {};
int playerCount = 0;
int loadOption = 1; // for delete record index

// int main()
// {
//     fstream file("loadGame.dat", ios::binary | ios::in | ios::out);
//     file.seekp(0);
//     player temp;
//     file.read(reinterpret_cast<char *>(&temp), sizeof(player));
//     file.read(reinterpret_cast<char *>(&Ball), sizeof(ball));
//     file.read(reinterpret_cast<char *>(&Paddle.width), sizeof(int));
//     file.read(reinterpret_cast<char *>(&Paddle.x), sizeof(int));
//     size_t len;
//     file.read(reinterpret_cast<char *>(&len), sizeof(len));
//     cout << sizeof(len) << endl;
//     cout << len;
// }
bool game(int)
{
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    system("cls");
    HideCursor(false);
    life = Player.life;
    score = Player.score;
    pauseOption = 1;
    renderPanel();
    auto lastTime2 = std::chrono::steady_clock::now();
    renderPanel();
    while (!gameOver)
    {
        auto currentTime = std::chrono::steady_clock::now();
        auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - lastTime2).count();

        // broken == 50?
        if (bricksCount())
        {
            nextStage();
            Sleep(1000);
            if (FPS < 120)
            {
                FPS += 20;
            }
            if (brickRow < 8)
            {
                brickRow++;
            }
            if (brickRow % 2 == 0 && brickCol < 14)
            {
                brickCol += 2;
            }
            initializeBricks();
            initializePaddle(Paddle, width);
            initializeBall(Ball);
        }
        auto frameStart = std::chrono::steady_clock::now();
        input();
        if (pauseOption == 2)
        {
            return false;
        }
        else if (pauseOption >= 2)
        {
            return true;
        }
        logic(Ball);
        SetConsoleCursorPosition(h, {0, 5});
        render();
        auto frameTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - frameStart).count();
        if (frameDelay > frameTime)
        {
            Sleep(frameDelay - frameTime); // تنظیم فاصله زمانی برای رسیدن به FPS ثابت
        }
    }
    if (gameOver == true)
    {
        life--;
    }
    while (life > 0)
    {

        HideCursor(false);
        initializePaddle(Paddle, width);
        initializeBall(Ball);
        COORD cursor = {0, 5};
        gameOver = false;
        auto lastTime = std::chrono::steady_clock::now();
        SetConsoleCursorPosition(h, cursor);
        render();
        renderPanel();
        char start = _getch();
        if (start == 27)
        {
            pauseMenu();
        }
        while (!gameOver)
        {
            auto currentTime = std::chrono::steady_clock::now();
            auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - lastTime).count();

            // broken == 50?
            if (bricksCount())
            {
                nextStage();
                Sleep(1000);
                if (FPS < 120)
                {
                    FPS += 20;
                }
                if (brickRow < 8)
                {
                    brickRow++;
                }
                if (brickRow % 2 == 0 && brickCol < 14)
                {
                    brickCol += 2;
                }
                initializeBricks();
                initializePaddle(Paddle, width);
                initializeBall(Ball);
            }
            input();
            if (pauseOption == 2)
            {
                return false;
            }
            else if (pauseOption >= 2)
            {
                return true;
            }
            if (elapsedTime > 75)
            {
                logic(Ball);
                SetConsoleCursorPosition(h, cursor);
                render();
                lastTime = currentTime;
            }
        }
        if (gameOver == true)
        {
            life--;
        }
    }
    return true;
}

bool game()
{
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    system("cls");
    HideCursor(false);
    initializeBricks();
    initializePaddle(Paddle, width);
    initializeBall(Ball);
    life = 3;
    score = 0;
    pauseOption = 1;
    Broken = 0;
    goldenCount = 0;
    TNTCount = 0;
    HardCount = 0;
    normalCount = 0;
    while (life > 0)
    {

        HideCursor(false);
        initializePaddle(Paddle, width);
        initializeBall(Ball);
        COORD cursor = {0, 5};
        gameOver = false;
        auto lastTime = std::chrono::steady_clock::now();
        SetConsoleCursorPosition(h, cursor);
        render();
        renderPanel();
        char start = _getch();
        if (start == 27)
        {
            pauseMenu();
        }
        while (!gameOver)
        {

            // broken == 50?
            if (bricksCount())
            {
                nextStage();
                Sleep(1000);
                if (brickRow < 8)
                {
                    brickRow++;
                }
                if (brickRow % 2 == 0 && brickCol < 14)
                {
                    brickCol += 2;
                }
                initializeBricks();
                initializePaddle(Paddle, width);
                initializeBall(Ball);
                SetConsoleCursorPosition(h, cursor);
                HideCursor(false);
                Broken = 0;
                render();
                renderPanel();
                _getch();
            }
            auto frameStart = std::chrono::steady_clock::now();
            input();
            if (pauseOption == 2)
            {
                return false;
            }
            else if (pauseOption >= 2)
            {
                return true;
            }
            logic(Ball);
            SetConsoleCursorPosition(h, cursor);
            render();
            auto frameTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - frameStart).count();
            if (frameDelay > frameTime)
            {
                Sleep(frameDelay - frameTime); // تنظیم فاصله زمانی برای رسیدن به FPS ثابت
            }
        }
        if (gameOver == true)
        {
            life--;
        }
    }
    return true;
}

void initializeBricks()
{
    int totalBrickWidth = brickCol * brickWidth + (brickCol - 1) * brickGap;

    int start = (width - totalBrickWidth) / 2;

    srand(time(0));
    for (int col = 0; col < brickCol; col++)
    {
        for (int row = 0; row < brickRow; row++)
        {
            bricks[col][row].x = start + col * (brickWidth + brickGap);
            bricks[col][row].y = row * 2 + 3;
            bricks[col][row].width = brickWidth;
            bricks[col][row].isBroken = false;
            int r = rand() % 100;
            if (r < 20)
            {
                bricks[col][row].color = 9;
            }
            else if (r < 40)
            {
                bricks[col][row].color = 10;
            }
            // else if (r < 60)
            // {
            //     bricks[col][row].color = 11;
            // }
            else if (r < 80)
            {
                bricks[col][row].color = 13;
            }
            else if (r < 90)
            {
                bricks[col][row].color = 12;
            }
            else
            {
                bricks[col][row].color = 14;
            }
            if (bricks[col][row].color == 9)
            {
                bricks[col][row].CTB = 2;
            }
            else
            {
                bricks[col][row].CTB = 1;
            }
        }
    }
}
void initializePaddle(paddle &Paddle, int width)
{
    Paddle.width = 7;
    Paddle.paddleChar = "━";
    Paddle.x = (width - Paddle.width) / 2;
}
void initializeBall(ball &Ball)
{
    srand(time(0));
    Ball.x = Paddle.x + 3;
    Ball.y = height - 3;

    int sign = rand() % 2;
    int value = rand() % 2 + 1;
    Ball.vx = sign == 0 ? 1 : -1;
    Ball.vy = value;
}
void render()
{
    for (int y = 0; y < 30; y++)
    {
        cout << setw(45) << "";
        for (int x = 0; x < 81; x++)
        {
            string c = " ";
            if (y == 0 && x == 0)
            {
                c = "┌";
            }
            else if (y == 29 && x == 0)
            {
                c = "└";
            }
            else if (y == 29 && x == 80)
            {
                c = "┘";
            }
            else if (y == 0 && x == 80)
            {
                c = "┐";
            }
            else if (y == 0 && (x > 0 && x < 80))
            {
                c = "─";
            }
            else if (y == 29 && (x > 0 && x < 80))
            {
                c = "─";
            }
            else if (x == 0 && (y > 0 && y < 29))
            {
                c = "│";
            }
            else if (x == 80 && (y > 0 && y < 29))
            {
                c = "│";
            }
            for (int col = 0; col < brickCol; col++)
            {
                for (int row = 0; row < brickRow; row++)
                {
                    if (y == bricks[col][row].y &&
                        x >= bricks[col][row].x &&
                        x < bricks[col][row].x + bricks[col][row].width && bricks[col][row].isBroken == false)
                    {
                        setColor(bricks[col][row].color);
                        c = "█";
                    }
                }
            }
            if (y == height - 2 &&
                x >= Paddle.x &&
                x < Paddle.x + Paddle.width)
            {
                c = Paddle.paddleChar;
            }

            if (x > 0 && x < width - 1 && y > 0 && y < height - 1)
            {
                if (x == Ball.x && y == Ball.y)
                    c = "●";
            }
            cout << c;
            setColor(7);
        }
        cout << endl;
    }
}
void render(string pause)
{
    for (int y = 0; y < 30; y++)
    {
        cout << setw(45) << "";
        for (int x = 0; x < 81; x++)
        {
            string c = " ";
            if (y == 0 && x == 0)
            {
                c = "┌";
            }
            else if (y == 29 && x == 0)
            {
                c = "└";
            }
            else if (y == 29 && x == 80)
            {
                c = "┘";
            }
            else if (y == 0 && x == 80)
            {
                c = "┐";
            }
            else if (y == 0 && (x > 0 && x < 80))
            {
                c = "─";
            }
            else if (y == 29 && (x > 0 && x < 80))
            {
                c = "─";
            }
            else if (x == 0 && (y > 0 && y < 29))
            {
                c = "│";
            }
            else if (x == 80 && (y > 0 && y < 29))
            {
                c = "│";
            }
            for (int col = 0; col < 10; col++)
            {
                for (int row = 0; row < 5; row++)
                {
                    if (y == bricks[col][row].y &&
                        x >= bricks[col][row].x &&
                        x < bricks[col][row].x + bricks[col][row].width && bricks[col][row].isBroken == false)
                    {
                        c = "█";
                    }
                }
            }
            if (y == height - 2 &&
                x >= Paddle.x &&
                x < Paddle.x + Paddle.width)
            {
                c = Paddle.paddleChar;
            }

            if (x > 0 && x < width - 1 && y > 0 && y < height - 1)
            {
                if (x == Ball.x && y == Ball.y)
                    c = "●";
            }
            cout << c;
        }
        cout << endl;
    }
}
void input()
{
    if (_kbhit())
    {
        char input = _getch();
        switch (input)
        {
        case 'D':
        case 'd':
        {
            if (Paddle.x + Paddle.width < 78 && (Ball.vx > 1 || Ball.vx < -1))
            {
                Paddle.x += 3;
            }
            else if (Paddle.x + Paddle.width < 79)
            {
                Paddle.x += 2;
            }
            break;
        }
        case 'A':
        case 'a':
        {
            if (Paddle.x > 3 && (Ball.vx > 1 || Ball.vx < -1))
            {
                Paddle.x -= 3;
            }
            else if (Paddle.x > 2)
            {
                Paddle.x -= 2;
            }
            break;
        }
        case 27:
        {
            pauseMenu();
            switch (pauseOption)
            {
            case 2:
            {
            }
            }
            break;
        }
        }
    }
}
void playBeep(int F, int T)
{
    thread t(Beep, F, T);
    t.detach();
}
void bricksLogic(brick &B, int i, int j)
{
    B.CTB--;
    if (B.color == 9 && B.CTB == 1)
    {
        playBeep(600 + 9 * 50, 60);
        B.color = 11;
    }
    if (B.CTB <= 0)
    {
        B.isBroken = true;

        if (B.color == 12)
        {
            TNTCount++;
            playBeep(600 + 12 * 50, 60);
            explodeBricks(i, j);
        }

        if (B.color == 14)
        {
            goldenCount++;
            playBeep(600 + 14 * 50, 60);
            score += 20;
        }
        else
        {
            if (B.color == 14)
            {
                HardCount++;
            }
            else
            {
                normalCount++;
            }
            playBeep(600, 60);
            score += 10;
        }
        Broken++;
        renderPanel();
    }
}
void logic(ball &)
{

    // endGame -> you will lose a life
    if (Ball.y >= height - 1)
    {
        // playBeep(200, 200);
        // playBeep(300, 100);
        // playBeep(400, 100);
        // playBeep(500, 100);
        playBeep(500, 300);
        playBeep(350, 400);
        playBeep(200, 600);
        gameOver = true;
    }

    // Wall Collision
    if (Ball.x >= width - 1 || Ball.x <= 1)
    {
        playBeep(520, 80);

        Ball.vx > 0 ? Ball.vx = 1 : Ball.vx = -1;
        Ball.vx *= -1;
    }
    if (Ball.y <= 1)
    {
        playBeep(520, 80);
        Ball.vy *= -1;
    }

    // Brick Collision
    bool collision = false;
    for (int i = 0; i < brickCol && !collision; i++)
    {
        for (int j = 0; j < brickRow; j++)
        {
            // from below
            if (Ball.x >= bricks[i][j].x - 1 &&
                Ball.x < bricks[i][j].x + bricks[i][j].width + 1 &&
                (Ball.y == bricks[i][j].y + 1) && bricks[i][j].isBroken == false && Ball.vy < 0)
            {
                collision = true;

                Ball.vx > 0 ? Ball.vx = 1 : Ball.vx = -1;
                Ball.vy > 0 ? Ball.vy = 1 : Ball.vy = -1;
                Ball.vy *= -1;
                if (j < brickRow - 1)
                {
                    if (((Ball.y + Ball.vy) == bricks[i][j + 1].y) &&
                        bricks[i][j + 1].isBroken == false && (Ball.x + Ball.vx >= bricks[i][j + 1].x) &&
                        (Ball.x + Ball.vx < bricks[i][j + 1].x + bricks[i][j + 1].width))
                    {
                        Ball.y = bricks[i][j + 1].y - 2;
                    }
                }

                bricksLogic(bricks[i][j], i, j);
                break;
            }

            // from left
            else if (Ball.x == bricks[i][j].x - 1 &&
                     (Ball.y >= bricks[i][j].y - 1 && Ball.y <= bricks[i][j].y + 1) &&
                     bricks[i][j].isBroken == false && Ball.vx > 0)
            {
                collision = true;

                Ball.vx > 0 ? Ball.vx = 1 : Ball.vx = -1;
                Ball.vy > 0 ? Ball.vy = 1 : Ball.vy = -1;
                Ball.vx *= -1;
                if (i > 0)
                {
                    // (Ball.x + Ball.vx) >= bricks[i - 1][j].x &&
                    if ((Ball.x + Ball.vx) >= bricks[i - 1][j].x &&
                        (Ball.x + Ball.vx) < bricks[i - 1][j].x + brickWidth &&
                        bricks[i - 1][j].isBroken == false && (Ball.y + Ball.vy == bricks[i - 1][j].y))
                    {
                        Ball.x += bricks[i - 1][j].x + brickWidth - 1 - (Ball.x + Ball.vx) + 1;
                    }
                }

                bricksLogic(bricks[i][j], i, j);
                break;
            }

            // from right
            else if (Ball.x == bricks[i][j].x + bricks[i][j].width + 1 &&
                     (Ball.y >= bricks[i][j].y - 1 && Ball.y <= bricks[i][j].y + 1) &&
                     bricks[i][j].isBroken == false && Ball.vx < 0)
            {
                collision = true;

                Ball.vx > 0 ? Ball.vx = 1 : Ball.vx = -1;
                Ball.vy > 0 ? Ball.vy = 1 : Ball.vy = -1;
                Ball.vx *= -1;
                if (i < brickCol - 1)
                {
                    // (Ball.x + Ball.vx) >= bricks[i - 1][j].x &&
                    if ((Ball.x + Ball.vx) >= bricks[i + 1][j].x &&
                        (Ball.x + Ball.vx) < bricks[i + 1][j].x + brickWidth &&
                        bricks[i + 1][j].isBroken == false && (Ball.y + Ball.vy == bricks[i + 1][j].y))
                    {
                        Ball.x -= Ball.x + Ball.vx - bricks[i + 1][j].x + 1;
                    }
                }

                bricksLogic(bricks[i][j], i, j);
                renderPanel();
                break;
            }
            // from above
            else if (Ball.x >= bricks[i][j].x - 1 &&
                     Ball.x < bricks[i][j].x + bricks[i][j].width + 1 &&
                     (Ball.y == bricks[i][j].y - 1) && bricks[i][j].isBroken == false && Ball.vy > 0)
            {
                collision = true;

                Ball.vx > 0 ? Ball.vx = 1 : Ball.vx = -1;
                Ball.vy > 0 ? Ball.vy = 1 : Ball.vy = -1;
                Ball.vy *= -1;
                if (j > 0)
                {
                    if (((Ball.y + Ball.vy) == bricks[i][j - 1].y) &&
                        bricks[i][j - 1].isBroken == false && (Ball.x + Ball.vx >= bricks[i][j - 1].x) && (Ball.x + Ball.vx < bricks[i][j - 1].x + bricks[i][j + 1].width))
                    {
                        Ball.y += 2;
                    }
                }

                bricksLogic(bricks[i][j], i, j);
                break;
            }
        }
    }
    int nextY = Ball.y + Ball.vx;

    // Paddle Collision
    int delta = 0;
    if (Ball.x >= Paddle.x &&
        Ball.x < Paddle.x + Paddle.width && Ball.y == height - 3)
    {
        playBeep(520, 80);
        Ball.vx > 0 ? Ball.vx = 1 : Ball.vx = -1;
        Ball.vy > 0 ? Ball.vy = 1 : Ball.vy = -1;
        int pos = Paddle.x + Paddle.width - Ball.x;
        switch (pos)
        {
        // case 0:
        case 2:
        case 1:
        {

            Ball.vy *= -1;
            if (Ball.x < 20 && Ball.vx < 0 && Ball.vx < 0)
            {
                Ball.vx *= -1;
            }
            Ball.vx > 0 ? delta = 2 : delta = 0;
            break;
        }
        // case 8:/
        case 6:
        case 7:
        {
            Ball.vy *= -1;
            if (Ball.x > width - 20 && Ball.vx > 0)
            {
                Ball.vx *= -1;
            }
            Ball.vx > 0 ? delta = 0 : delta = -2;
            break;
        }

        case 4:
        {
            // srand(time(0));
            // Ball.vx = (rand() % 2 == 0) ? 1 : -1;
        }
        case 5:
        case 3:
        {
            // Ball.vx = 0;
            Ball.vy *= -1;
            break;
        }
        }
    }
    Ball.vx += delta;

    if (Ball.x + Ball.vx > width - 1)
    {
        Ball.x = width - 1;
    }
    else if (Ball.x + Ball.vx < 1)
    {
        Ball.x = 1;
    }
    else
    {
        Ball.x += Ball.vx;
    }
    Ball.y += Ball.vy;
}
bool bricksCount()
{
    for (int i = 0; i < brickCol; i++)
    {
        for (int j = 0; j < brickRow; j++)
        {
            if (bricks[i][j].isBroken == false)
            {
                return false;
            }
        }
    }
    return true;
}
void renderPanel()
{
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(h, {panelx, panely});
    cout << "┌───────────────────┐";
    SetConsoleCursorPosition(h, {panelx, panely + 1});
    cout << "│     Game Info     │";
    SetConsoleCursorPosition(h, {panelx, panely + 2});
    cout << "├───────────────────┤";
    SetConsoleCursorPosition(h, {panelx, panely + 3});
    cout << "│ Score:      " << setw(5) << score << " │";
    SetConsoleCursorPosition(h, {panelx, panely + 4});
    cout << "│ Life:       " << setw(5) << life << " │";
    SetConsoleCursorPosition(h, {panelx, panely + 5});
    cout << "│ Bricks:     " << setw(5) << (brickCol * brickRow) - Broken << " │";
    SetConsoleCursorPosition(h, {panelx, panely + 6});
    cout << "└───────────────────┘";
}
void selectPO(int option, int crrOption) // PO: pause option
{
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);

    if (option == crrOption)
    {
        SetConsoleTextAttribute(h, 1);
    }
    else
    {
        SetConsoleTextAttribute(h, 15);
    }
}
void pauseMenu()
{
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(h, 8);
    SetConsoleCursorPosition(h, {0, 5});
    render("pause");
    renderPanel();
    SetConsoleTextAttribute(h, 15);
    SetConsoleCursorPosition(h, {65, 13});
    cout << "╔══════════════════PAUSE══════════════════╗";
    for (int i = 0; i < 13; i++)
    {
        SetConsoleCursorPosition(h, {65, SHORT(14 + i)});
        cout << "║                                         ║";
    }
    SetConsoleCursorPosition(h, {65, 26});
    SetConsoleTextAttribute(h, 15);
    cout << "╚═════════════════════════════════════════╝";
    while (true)
    {
        selectPO(1, pauseOption);
        SetConsoleCursorPosition(h, {80, 14});
        cout << "╔═══════════╗";
        SetConsoleCursorPosition(h, {80, 15});
        cout << "║   Resume  ║";
        SetConsoleCursorPosition(h, {80, 16});
        cout << "╚═══════════╝";
        selectPO(2, pauseOption);
        SetConsoleCursorPosition(h, {80, 17});
        cout << "╔═══════════╗";
        SetConsoleCursorPosition(h, {80, 18});
        cout << "║  Restart  ║";
        SetConsoleCursorPosition(h, {80, 19});
        cout << "╚═══════════╝";
        selectPO(3, pauseOption);
        SetConsoleCursorPosition(h, {80, 20});
        cout << "╔═══════════╗";
        SetConsoleCursorPosition(h, {80, 21});
        cout << "║ Save Game ║";
        SetConsoleCursorPosition(h, {80, 22});
        cout << "╚═══════════╝";
        selectPO(4, pauseOption);
        SetConsoleCursorPosition(h, {80, 23});
        cout << "╔═══════════╗";
        SetConsoleCursorPosition(h, {80, 24});
        cout << "║   Quit    ║";
        SetConsoleCursorPosition(h, {80, 25});
        cout << "╚═══════════╝";
        while (true)
        {
            if (_kbhit())
            {
                char userInput = _getch();
                if ((userInput == 'w' || userInput == 'W') && pauseOption > 1)
                {
                    pauseOption -= 1;
                    break;
                }
                else if ((userInput == 's' || userInput == 'S') && pauseOption < 4)
                {
                    pauseOption += 1;
                    break;
                }
                if (userInput == 13)
                {
                    if (pauseOption <= 2)
                    {
                        SetConsoleTextAttribute(h, 7);
                        renderPanel();
                    }
                    return;
                }
            }
        }
        Sleep(10);
    }
}
void setColor(int color)
{
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(h, color);
}
void explodeBricks(int col, int row)
{
    for (int dx = -1; dx <= 1; dx++)
    {
        for (int dy = -1; dy <= 1; dy++)
        {
            if (dx == 0 && dy == 0)
                continue;
            int c = col + dx;
            int r = row + dy;
            if (c >= 0 && c < brickCol && r >= 0 && r < brickRow)
            {
                if (!bricks[c][r].isBroken && !(c == col && r == row))
                {
                    bricks[c][r].isBroken = true;
                    if (bricks[c][r].color == 14)
                    {
                        goldenCount++;
                        score += 20;
                    }
                    else
                    {
                        if (bricks[c][r].color == 9 || bricks[c][r].color == 11)
                        {
                            HardCount++;
                        }
                        else
                        {
                            normalCount++;
                        }
                        score += 10;
                    }
                    Broken++;
                }
            }
        }
    }
}
void saveHistory()
{
    time_t now = time(nullptr);
    tm *local = localtime(&now);
    strftime(Player.date, 80, "%Y-%m(%b)-%d(%a)", local);
    strftime(Player.time, 80, "%H:%M", local);

    char *pointer = strstr(Player.name, "(auto save)"); // پیدا کردن کلمه
    if (pointer != NULL)
    {
        int length = strlen("(auto save)");
        // کپی کردن ادامه رشته روی بخش پیدا شده
        strcpy(pointer, pointer + length);
    }
    ofstream file("history.txt", ios::app);
    if (file.fail())
        return;
    file << Player.name << " "
         << Player.date << " "
         << Player.time << " "
         << score << endl; // PLayer.score = scores
    file.close();

    ofstream scores("scores.txt", ios::out | ios::app);
    if (scores.fail())
        return;
    scores << Player.name << " "
           << goldenCount << " "
           << TNTCount << " "
           << HardCount << " "
           << normalCount << endl;
    scores.close();
}
void loadScoresAndPrint(char name[])
{
    // T: Tmep
    string Tname;
    int TgoldenCount = 0;
    int TeTNTCount = 0;
    int THardCount = 0;
    int TnormalCount = 0;
    ifstream scores("scores.txt", ios::in);
    if (scores.fail())
        return;
    while (scores >> Tname >> TgoldenCount >> TNTCount >> THardCount >> TnormalCount)
    {
        if (Tname == name)
        {
            break;
        }
    }
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    system("cls");
    setColor(7);
    SetConsoleCursorPosition(h, {68, 15});
    cout << "╔══════════════════════════════╗";
    SetConsoleCursorPosition(h, {68, 16});
    cout << "║                              ║";
    SetConsoleCursorPosition(h, {68, 17});
    cout << "║           "; setColor(5); cout << "YOU HEAT "; setColor(7); cout <<"          ║";
    SetConsoleCursorPosition(h, {68, 18});
    cout << "║            " << "\033[38;5;196mTNT: " << TNTCount; 
    SetConsoleCursorPosition(h, {99, 18});
    cout << "\033[0m║";
    SetConsoleCursorPosition(h, {68, 19});
    cout << "║                              ║";
    SetConsoleCursorPosition(h, {68, 20});
    cout << "║            " << "\033[38;5;226mGolden: " << TgoldenCount; 
    SetConsoleCursorPosition(h, {99, 20});
    cout << "\033[0m║";
    SetConsoleCursorPosition(h, {68, 21});
    cout << "║                              ║";
    SetConsoleCursorPosition(h, {68, 22});
    cout << "║            " << "\033[38;5;33mHard: " << THardCount;
    SetConsoleCursorPosition(h, {99, 22});
    cout << "\033[0m║";
    SetConsoleCursorPosition(h, {68, 23});
    cout << "║                              ║";
    SetConsoleCursorPosition(h, {68, 24});
    cout << "║            " << "\033[38;5;181mNormal: " << TnormalCount;
    SetConsoleCursorPosition(h, {99, 24});
    cout << "\033[0m║";
    SetConsoleCursorPosition(h, {68, 25});
    cout << "\033[0m╚══════════════════════════════╝";
}
int sort()
{
    if (historyCount == 1)
    {
        return history[0].score;
    }
    int high;
    for (int i = 0; i < historyCount - 1; i++)
    {
        for (int j = 0; j < historyCount - i - 1; j++)
        {
            if (history[j].score < history[j + 1].score)
            {
                swap(history[j], history[j + 1]);
            }
        }
    }
    return history[0].score;
}
void loadHistory()
{
    historyCount = 0;
    ifstream file("history.txt");
    file.seekg(0);
    if (file.is_open())
    {
        while (file >> history[historyCount].name >> history[historyCount].date >> history[historyCount].time >> history[historyCount].score)
        {
            historyCount++;
        }
    }
    file.close();
}
int Hoption = 1; // History option
void setHoptioncolor(int crrOption, int option)
{
    if (crrOption == option)
    {
        setColor(13);
    }
    else
    {
        setColor(7);
    }
}
bool printHistory(int historyCount)
{
    setColor(5);
    system("cls");
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(h, {54, 3});
    cout << "==============================================================\n";
    cout << setw(54) << "" << "                        GAME HISTORY\n";
    cout << setw(54) << "" << "==============================================================\n\n";
    cout << setw(54) << "";
    cout << left
         << setw(6) << "Rank"
         << setw(15) << "Name"
         << setw(25) << "Date"
         << setw(10) << "Time"
         << setw(10) << "Score"
         //  << setw(8) << "Lives"
         //  << setw(8) << "Result"
         << endl;

    cout << setw(54) << "" << "--------------------------------------------------------------\n";

    setColor(7);
    while (true)
    {
        SetConsoleCursorPosition(h, {0, 9});
        for (int i = 0; i < historyCount; i++)
        {
            setHoptioncolor(Hoption, i + 1);
            cout << setw(54) << "";
            cout << left
                 << setw(6) << i + 1
                 << setw(15) << history[i].name
                 << setw(25) << history[i].date
                 << setw(10) << history[i].time
                 << setw(10) << history[i].score
                 //  << setw(8) << history[i].life
                 //  << setw(8) << (history[i].win ? "WIN" : "LOSE")
                 << endl;
        }
        setColor(5);
        cout << setw(54) << "" << "==============================================================\n";
        while (true)
        {
            if (_kbhit())
            {
                char userInput = _getch();
                if ((userInput == 'w' || userInput == 'W') && Hoption > 1)
                {
                    Hoption -= 1;
                    break;
                }
                else if ((userInput == 's' || userInput == 'S') && Hoption < historyCount)
                {
                    Hoption += 1;
                    break;
                }
                else if (userInput == 13)
                {
                    return true;
                }
                else if (userInput == 8)
                {

                    return false;
                }
            }
        }
    }
    setColor(7);
    _getch();
}
void saveGame(player &p)
{
    p.score = score;
    p.life = life;
    p.isActive = false;
    time_t now = time(nullptr);
    tm *local = localtime(&now);
    strftime(Player.date, 80, "%Y-%m(%b)-%d(%a)", local);
    strftime(Player.time, 80, "%H:%M", local);
    // maybe ios::app
    ofstream fOut("loadGame.dat", ios::app | ios::binary);
    if (fOut.is_open())
    {
        fOut.write(reinterpret_cast<char *>(&p), sizeof(player));
        fOut.write(reinterpret_cast<char *>(&Ball), sizeof(ball));

        fOut.write(reinterpret_cast<char *>(&Paddle.width), sizeof(int));
        fOut.write(reinterpret_cast<char *>(&Paddle.x), sizeof(int));
        size_t len = Paddle.paddleChar.size();
        fOut.write(reinterpret_cast<char *>(&len), sizeof(len));
        fOut.write(Paddle.paddleChar.c_str(), len);

        fOut.write(reinterpret_cast<char *>(&brickCol), sizeof(int));
        fOut.write(reinterpret_cast<char *>(&brickRow), sizeof(int));
        fOut.write(reinterpret_cast<char *>(&bricks), sizeof(brick) * brickCol * brickRow);
        fOut.write(reinterpret_cast<char *>(&Broken), sizeof(int));
        fOut.write(reinterpret_cast<char *>(&goldenCount), sizeof(int));
        fOut.write(reinterpret_cast<char *>(&TNTCount), sizeof(int));
        fOut.write(reinterpret_cast<char *>(&HardCount), sizeof(int));
        fOut.write(reinterpret_cast<char *>(&normalCount), sizeof(int));
    }
    fOut.seekp(0, ios::end);
    fOut.close();
}

// Half AI
void setAndMarkAsActive(int index)
{
    // باز کردن فایل در حالت خواندن و نوشتن همزمان (ios::in | ios::out)
    fstream file("loadGame.dat", ios::binary | ios::in | ios::out);
    int count = 1;
    player temp;
    if (file.is_open())
    {
        if (index == 1)
        {
            while (file.read(reinterpret_cast<char *>(&temp), sizeof(player)))
            {
                if (temp.isActive == false)
                {
                    int pointer = file.tellp();
                    int pos = pointer - sizeof(player);

                    temp.isActive = true;
                    char *find = strstr(temp.name, "(auto save)"); // پیدا کردن کلمه
                    if (find != NULL)
                    {
                        int length = strlen("(auto save)");
                        // کپی کردن ادامه رشته روی بخش پیدا شده
                        strcpy(find, find + length);
                    }
                    Player = temp;
                    file.read(reinterpret_cast<char *>(&Ball), sizeof(ball));

                    file.read(reinterpret_cast<char *>(&Paddle.width), sizeof(int));
                    file.read(reinterpret_cast<char *>(&Paddle.x), sizeof(int));
                    size_t len;
                    file.read(reinterpret_cast<char *>(&len), sizeof(len)); // خواندن طول
                    Paddle.paddleChar.resize(len);                          // آماده‌سازی فضا برای استرینگ
                    file.read(&Paddle.paddleChar[0], len);                  // خواندن متن

                    file.read(reinterpret_cast<char *>(&brickCol), sizeof(int));
                    file.read(reinterpret_cast<char *>(&brickRow), sizeof(int));
                    file.read(reinterpret_cast<char *>(&bricks), sizeof(brick) * brickCol * brickRow);
                    file.read(reinterpret_cast<char *>(&Broken), sizeof(int));
                    file.read(reinterpret_cast<char *>(&goldenCount), sizeof(int));
                    file.read(reinterpret_cast<char *>(&TNTCount), sizeof(int));
                    file.read(reinterpret_cast<char *>(&HardCount), sizeof(int));
                    file.read(reinterpret_cast<char *>(&normalCount), sizeof(int));
                    file.seekp(pos);
                    file.write(reinterpret_cast<char *>(&Player), sizeof(player));
                    break;
                }
                file.read(reinterpret_cast<char *>(&Ball), sizeof(ball));
                file.read(reinterpret_cast<char *>(&Paddle.width), sizeof(int));
                file.read(reinterpret_cast<char *>(&Paddle.x), sizeof(int));
                size_t len;
                file.read(reinterpret_cast<char *>(&len), sizeof(len)); // خواندن طول
                Paddle.paddleChar.resize(len);                          // آماده‌سازی فضا برای استرینگ
                file.read(&Paddle.paddleChar[0], len);                  // خواندن متن

                file.read(reinterpret_cast<char *>(&brickCol), sizeof(int));
                file.read(reinterpret_cast<char *>(&brickRow), sizeof(int));
                file.read(reinterpret_cast<char *>(&bricks), sizeof(brick) * brickCol * brickRow);
                file.read(reinterpret_cast<char *>(&Broken), sizeof(int));
                file.read(reinterpret_cast<char *>(&goldenCount), sizeof(int));
                file.read(reinterpret_cast<char *>(&TNTCount), sizeof(int));
                file.read(reinterpret_cast<char *>(&HardCount), sizeof(int));
                file.read(reinterpret_cast<char *>(&normalCount), sizeof(int));
            }
        }
        else
        {
            while (count < index)
            {
                file.read(reinterpret_cast<char *>(&temp), sizeof(player));
                if (temp.isActive == false)
                {
                    count++;
                }
                file.read(reinterpret_cast<char *>(&Ball), sizeof(ball));
                file.read(reinterpret_cast<char *>(&Paddle.width), sizeof(int));
                file.read(reinterpret_cast<char *>(&Paddle.x), sizeof(int));
                size_t len;
                file.read(reinterpret_cast<char *>(&len), sizeof(len)); // خواندن طول
                Paddle.paddleChar.resize(len);                          // آماده‌سازی فضا برای استرینگ
                file.read(&Paddle.paddleChar[0], len);                  // خواندن متن

                file.read(reinterpret_cast<char *>(&brickCol), sizeof(int));
                file.read(reinterpret_cast<char *>(&brickRow), sizeof(int));
                file.read(reinterpret_cast<char *>(&bricks), sizeof(brick) * brickCol * brickRow);
                file.read(reinterpret_cast<char *>(&Broken), sizeof(int));
                file.read(reinterpret_cast<char *>(&goldenCount), sizeof(int));
                file.read(reinterpret_cast<char *>(&TNTCount), sizeof(int));
                file.read(reinterpret_cast<char *>(&HardCount), sizeof(int));
                file.read(reinterpret_cast<char *>(&normalCount), sizeof(int));
            }
            while (file.read(reinterpret_cast<char *>(&temp), sizeof(player)))
            {
                if (temp.isActive == false)
                {
                    int pointer = file.tellp();
                    int pos = pointer - sizeof(player);

                    temp.isActive = true;
                    char *find = strstr(temp.name, "(auto save)"); // پیدا کردن کلمه
                    if (find != NULL)
                    {
                        int length = strlen("(auto save)");
                        // کپی کردن ادامه رشته روی بخش پیدا شده
                        strcpy(find, find + length);
                    }
                    Player = temp;
                    file.read(reinterpret_cast<char *>(&Ball), sizeof(ball));

                    file.read(reinterpret_cast<char *>(&Paddle.width), sizeof(int));
                    file.read(reinterpret_cast<char *>(&Paddle.x), sizeof(int));
                    size_t len;
                    file.read(reinterpret_cast<char *>(&len), sizeof(len)); // خواندن طول
                    Paddle.paddleChar.resize(len);                          // آماده‌سازی فضا برای استرینگ
                    file.read(&Paddle.paddleChar[0], len);                  // خواندن متن

                    file.read(reinterpret_cast<char *>(&brickCol), sizeof(int));
                    file.read(reinterpret_cast<char *>(&brickRow), sizeof(int));
                    file.read(reinterpret_cast<char *>(&bricks), sizeof(brick) * brickCol * brickRow);
                    file.read(reinterpret_cast<char *>(&Broken), sizeof(int));
                    file.read(reinterpret_cast<char *>(&goldenCount), sizeof(int));
                    file.read(reinterpret_cast<char *>(&TNTCount), sizeof(int));
                    file.read(reinterpret_cast<char *>(&HardCount), sizeof(int));
                    file.read(reinterpret_cast<char *>(&normalCount), sizeof(int));
                    file.seekp(pos);
                    file.write(reinterpret_cast<char *>(&Player), sizeof(player));
                    break;
                }
                file.read(reinterpret_cast<char *>(&Ball), sizeof(ball));
                file.read(reinterpret_cast<char *>(&Paddle.width), sizeof(int));
                file.read(reinterpret_cast<char *>(&Paddle.x), sizeof(int));
                size_t len;
                file.read(reinterpret_cast<char *>(&len), sizeof(len)); // خواندن طول
                Paddle.paddleChar.resize(len);                          // آماده‌سازی فضا برای استرینگ
                file.read(&Paddle.paddleChar[0], len);                  // خواندن متن

                file.read(reinterpret_cast<char *>(&brickCol), sizeof(int));
                file.read(reinterpret_cast<char *>(&brickRow), sizeof(int));
                file.read(reinterpret_cast<char *>(&bricks), (sizeof(brick) * brickCol * brickRow));
                file.read(reinterpret_cast<char *>(&Broken), sizeof(int));
                file.read(reinterpret_cast<char *>(&goldenCount), sizeof(int));
                file.read(reinterpret_cast<char *>(&TNTCount), sizeof(int));
                file.read(reinterpret_cast<char *>(&HardCount), sizeof(int));
                file.read(reinterpret_cast<char *>(&normalCount), sizeof(int));
            }
        }
        file.close();
    }
}
void setLGOColor(int crrOption, int option) // LGO : Load Game Option
{
    if (crrOption == option)
    {
        setColor(14);
    }
    else
    {
        setColor(15);
    }
}
void loadPlayer()
{
    playerCount = 0;
    // int count = 0;
    ifstream fIn("loadGame.dat", ios::in | ios::binary);
    player temp;
    // int index = sizeof(ball) + sizeof(paddle) + sizeof(bricks) + sizeof(int);
    fIn.seekg(0);
    if (fIn.is_open())
    {
        while (fIn.read(reinterpret_cast<char *>(&temp), sizeof(player)))
        {
            if (temp.isActive == false)
            {
                loadedPlayer[playerCount] = temp;
                playerCount++;
            }
            fIn.read(reinterpret_cast<char *>(&Ball), sizeof(ball));
            fIn.read(reinterpret_cast<char *>(&Paddle.width), sizeof(int));
            fIn.read(reinterpret_cast<char *>(&Paddle.x), sizeof(int));
            size_t len;
            fIn.read(reinterpret_cast<char *>(&len), sizeof(len)); // خواندن طول
            Paddle.paddleChar.resize(len);                         // آماده‌سازی فضا برای استرینگ
            fIn.read(&Paddle.paddleChar[0], len);                  // خواندن متن

            fIn.read(reinterpret_cast<char *>(&brickCol), sizeof(int));
            fIn.read(reinterpret_cast<char *>(&brickRow), sizeof(int));
            fIn.read(reinterpret_cast<char *>(&bricks), sizeof(brick) * brickCol * brickRow);
            fIn.read(reinterpret_cast<char *>(&Broken), sizeof(int));
            fIn.read(reinterpret_cast<char *>(&goldenCount), sizeof(int));
            fIn.read(reinterpret_cast<char *>(&TNTCount), sizeof(int));
            fIn.read(reinterpret_cast<char *>(&HardCount), sizeof(int));
            fIn.read(reinterpret_cast<char *>(&normalCount), sizeof(int));
        }
    }
    fIn.close();
}
bool printLoadGame()
{
    setColor(6);
    loadOption = 1;
    system("cls");
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(h, {51, 3});
    cout << "=================================================================\n";
    cout << setw(51) << "" << "                           LOAD GAME\n";
    cout << setw(51) << "" << "=================================================================\n\n";
    cout << setw(51) << "";
    cout << left
         << setw(4) << "#"
         << setw(15) << "Name"
         << setw(10) << "Score"
         << setw(8) << "Lives"
         << setw(22) << "Date"
         << setw(10) << "Time"
         << endl;

    cout << setw(51) << "" << "-----------------------------------------------------------------\n";
    while (true)
    {
        SetConsoleCursorPosition(h, {0, 9});
        for (int i = 0; i < playerCount; i++)
        {
            setLGOColor(loadOption, i + 1);
            cout << setw(51) << "";
            cout << "|" << left
                 << setw(3) << i + 1
                 << setw(15) << loadedPlayer[i].name
                 << setw(10) << loadedPlayer[i].score
                 << setw(8) << loadedPlayer[i].life
                 << setw(22) << loadedPlayer[i].date
                 << setw(10) << loadedPlayer[i].time
                 << endl;
            if (i < playerCount - 1)
            {
                setColor(15);
                cout << setw(51) << "" << "-----------------------------------------------------------------\n";
            }
        }
        setColor(6);
        cout << setw(51) << "" << "=================================================================\n";
        while (true)
        {
            if (_kbhit())
            {
                char userInput = _getch();
                if ((userInput == 'w' || userInput == 'W') && loadOption > 1)
                {
                    loadOption -= 1;
                    break;
                }
                else if ((userInput == 's' || userInput == 'S') && loadOption < playerCount)
                {
                    loadOption += 1;
                    break;
                }
                else if (userInput == 13)
                {
                    if (playerCount > 0)
                    {
                        return true;
                    }
                }
                else if (userInput == 8)
                {

                    return false;
                }
            }
        }
    }
    setColor(7);
}
void nextStage()
{
    HideCursor(true);
    system("cls");
    string newGame[35][80];
    for (int H = 0; H < 35; H++)
    {
        for (int S = 0; S < 80; S++)
        {
            newGame[H][S] = " ";
        }
    }
    newGame[0][0] = "╔";
    newGame[0][54] = "╗";
    newGame[34][0] = "╚";
    newGame[34][54] = "╝";
    for (int i = 1; i < 34; i++)
    {
        newGame[i][0] = "║";
        newGame[i][54] = "║";
    }
    for (int i = 1; i < 54; i++)
    {
        newGame[0][i] = "═";
        newGame[34][i] = "═";
    }
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(h, {0, 14});
    for (int i = 0; i < 10; i++)
    {
        cout << setw(60) << "";
        for (int j = 0; j < 79; j++)
        {
            cout << newGame[i][j];
        }
        cout << endl;
    }
    SetConsoleCursorPosition(h, {60, 23});
    cout << "╚═════════════════════════════════════════════════════╝";
    SetConsoleTextAttribute(h, 12);
    SetConsoleCursorPosition(h, {85, 18});
    cout << "Great";
    SetConsoleCursorPosition(h, {77, 19});
    cout << "Loading next stage...";
    SetConsoleTextAttribute(h, 7);
}