#include <SDL3/SDL.h>

#include <iostream>
#include <vector>
#include <random>
#include <algorithm>

void narisi();
constexpr int WIDTH  = 900;
constexpr int HEIGHT = 600;
constexpr int CELL = 40;
constexpr int COLS = WIDTH / CELL;
constexpr int ROWS = HEIGHT / CELL;
constexpr int NUMBER_OF_OBSTACLES = 30;
constexpr int WALL_COL = COLS - 2;

SDL_Renderer* renderer = nullptr;
SDL_Window* window = nullptr;

int robotX = 1;
int robotY = ROWS / 2;

std::vector<std::pair<int, int>> obstacles;
int gapY;

bool gameOver = false;
bool success = false;

int steps = 0;

std::random_device rd;
std::mt19937 generator(rd());

bool jeOviro(int x, int y){
    for (const auto& obstacle : obstacles){
        if (obstacle.first == x && obstacle.second == y)return true;
    }
    return false;
}

bool jeZid(int x, int y){
    if (x != WALL_COL) return false;
    return y != gapY;
}

bool jeProsto(int x, int y){
    if (x < 0 || x >= COLS || y < 0 || y >= ROWS) return false;
    if (jeZid(x, y)) return false;
    if (jeOviro(x, y)) return false;
    return true;
}

void obdelajDogodke(){
    SDL_Event event;
    while (SDL_PollEvent(&event)){
        if (event.type == SDL_EVENT_QUIT) gameOver = true;
    }
}

void ustvariIgro(){
    obstacles.clear();
    gameOver = false;
    success = false;
    steps = 0;
    robotX = 1;
    robotY = ROWS / 2;

    std::uniform_int_distribution<int> gapDistribution(1, ROWS - 2);
    gapY = gapDistribution(generator);
    std::vector<std::pair<int, int>> pot;
    int x = robotX;
    int y = robotY;
    while (y != gapY){
        pot.push_back({x, y});
        if (y < gapY) ++y;
        else --y;
    }
    while (x <= WALL_COL){
        pot.push_back({x, y});
        ++x;
    }

    std::uniform_int_distribution<int> xDistribution(2, WALL_COL - 2);
    std::uniform_int_distribution<int> yDistribution(0, ROWS - 1);

    while (static_cast<int>(obstacles.size()) < NUMBER_OF_OBSTACLES){
        int ox = xDistribution(generator);
        int oy = yDistribution(generator);

        if (ox == robotX && oy == robotY) continue;
        bool naPoti = false;
        for (const auto& p : pot) {
            if (p.first == ox && p.second == oy) {
                naPoti = true;
                break;
            }
        }
        if (naPoti) continue;
        if (jeOviro(ox, oy)) continue;
        obstacles.push_back({ox, oy});
    }
}

bool naCilju(){
    return robotX > WALL_COL;
}

bool odprtinaSpredaj(){
    return robotX + 1 == WALL_COL && robotY == gapY;
}

void premakni(int dx, int dy){
    if (gameOver || success) return;
    obdelajDogodke();
    int novaX = robotX + dx;
    int novaY = robotY + dy;
    ++steps;

    if (novaX < 0 || novaX > WALL_COL ||  novaY < 0 || novaY >= ROWS) {
        gameOver = true;
        std::cout << "\nRobot je zapustil igralno polje."<<std::endl;
        std::cout<< "Stevilo korakov: " << steps << std::endl;
        return;
    }

    if (jeOviro(novaX, novaY)) {
        gameOver = true;
        std::cout << "TRK Z Oviro!"<<std::endl;
        std::cout<< "Stevilo korakov: "<< steps << std::endl;;
        return;
    }

    if (jeZid(novaX, novaY)) {
        gameOver = true;
        std::cout << "TRK Z ZIDOM!" << std::endl;
        std::cout << "Stevilo korakov: " << steps << std::endl;
        return;
    }

    robotX = novaX;
    robotY = novaY;

    if (naCilju()){
        success = true;
        std::cout<< "=============================="<<std::endl;
        std::cout<< "          USPESNO!" << std::endl;
        std::cout<< "=============================="<<std::endl;
        std::cout << "Stevilo korakov: " << steps << std::endl;
    }
    narisi();
    SDL_Delay(80);
}

void naprej(){
    premakni(1, 0);
}

void nazaj(){
    premakni(-1, 0);
}

void gor(){
    premakni(0, -1);
}

void dol(){
    premakni(0, 1);
}

bool oviraSpredaj(){
    int x = robotX + 1;
    int y = robotY;
    return !jeProsto(x, y);
}

bool oviraZadaj(){
    int x = robotX - 1;
    int y = robotY;
    return !jeProsto(x, y);
}

bool oviraLevo(){
    int x = robotX;
    int y = robotY - 1;
    return !jeProsto(x, y);
}

bool oviraDesno(){
    int x = robotX;
    int y = robotY + 1;
    return !jeProsto(x, y);
}

bool koncano(){
    return gameOver || success;
}

void narisi(){
    SDL_SetRenderDrawColor(renderer, 25, 25, 30, 255);
    SDL_RenderClear(renderer);
    SDL_SetRenderDrawColor(renderer, 45, 45, 50, 255);

    for (int x = 0; x <= WIDTH; x += CELL)
        SDL_RenderLine(renderer, static_cast<float>(x), 0.0f, static_cast<float>(x), static_cast<float>(HEIGHT));

    for (int y = 0; y <= HEIGHT; y += CELL)
        SDL_RenderLine(renderer, 0.0f, static_cast<float>(y), static_cast<float>(WIDTH), static_cast<float>(y));

    SDL_SetRenderDrawColor(renderer, 120, 120, 120, 255);

    for (int y = 0; y < ROWS; ++y){
        if (y == gapY) continue;
        SDL_FRect wall{WALL_COL * CELL, y * CELL, CELL, CELL};
        SDL_RenderFillRect(renderer, &wall);
    }

    SDL_SetRenderDrawColor(renderer, 50, 180, 80, 255);
    SDL_FRect gap{WALL_COL * CELL, gapY * CELL, CELL, CELL};
    SDL_RenderRect(renderer, &gap);
    SDL_SetRenderDrawColor(renderer, 220, 150, 40, 255);

    for (const auto& obstacle : obstacles){
        SDL_FRect r{obstacle.first * CELL, obstacle.second * CELL, CELL, CELL};
        SDL_RenderFillRect(renderer, &r);
    }

    SDL_SetRenderDrawColor(renderer, 70, 150, 255, 255);
    SDL_FRect r{robotX * CELL, robotY * CELL, CELL, CELL};
    SDL_RenderFillRect(renderer, &r);
    SDL_RenderPresent(renderer);
}

void programUdelezenca(){
    /*
                         TVOJA NALOGA

    Spravi modri kvadratek skozi zeleno odprtino.
    Ob vsakem zagonu se ovire in odprtina
    postavijo drugače.

    Na voljo imaš:
        naprej();
        nazaj();
        gor();
        dol();

    Senzorji:
        oviraSpredaj();
        oviraZadaj();
        oviraLevo();
        oviraDesno();

    Senzor vrne:
        true  -> v tej smeri je ovira
        false -> pot je prosta

    Dodatno:
        odprtinaSpredaj()
        vrne true, če je neposredno pred robotom
        odprtina v zidu.

        koncano()
        vrne true, ko je igra končana.

    PRIMER:
        if (!oviraSpredaj()){
            naprej();
        }
    */

    // TVOJA KODA
}

int main(){
    if (!SDL_Init(SDL_INIT_VIDEO)){
        std::cerr << "SDL napaka: " << SDL_GetError() << std::endl;
        return 1;
    }

    if (!SDL_CreateWindowAndRenderer("Programiranje zank",  WIDTH, HEIGHT, 0, &window, &renderer)) {
        std::cerr << "Napaka pri ustvarjanju okna: " << SDL_GetError() << std::endl;
        SDL_Quit();
        return 1;
    }

    ustvariIgro();
    narisi();
    programUdelezenca();
    bool running = true;
    while (running) {
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_EVENT_QUIT) running = false;
        }
        SDL_Delay(10);
    }
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}