#define SDL_MAIN_USE_CALLBACKS 1
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3_ttf/SDL_ttf.h>
#include <SDL3_image/SDL_image.h>
#include "Core.h"
#include <string>
#include "Snake/World.h"
#include "Snake/Snake.h"

SDL_Window* Window{};
SDL_Renderer* Renderer{};
TTF_Font* Font{};
FGameObject GameObject;


void Update(float DeltaTime);

SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[])
{
    SDL_SetAppMetadata("Basic SDL3 App", "1.0", "com.example.MyGame");

    if (!SDL_Init(SDL_INIT_EVENTS | SDL_INIT_VIDEO))
    {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Init failed (%s)", SDL_GetError());
        return SDL_APP_FAILURE;
    }
    if (!TTF_Init())
    {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "TTF_Init failed (%s)", SDL_GetError());
        return SDL_APP_FAILURE;
    }
    if (!MIX_Init())
    {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "MIX_Init failed (%s)", SDL_GetError());
        return SDL_APP_FAILURE;
    }

    if (!SDL_CreateWindowAndRenderer("examples/MyGame", 40 * TileSize, 20 * TileSize, 0, &Window, &Renderer))
    {
        SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
    std::string FontPath = std::string(SDL_GetBasePath()) + "allerrg.ttf";
    Font = TTF_OpenFont(FontPath.c_str(), 48.0f);
    if (!Font)
    {
        SDL_Log("Couldn't open font [%s]: %s", FontPath.c_str(), SDL_GetError());
        return SDL_APP_FAILURE;
    }

    GameObject.TileMap = IMG_LoadTexture(Renderer, (std::string(SDL_GetBasePath()) + "snake.png").c_str());
    if (!GameObject.TileMap)
    {
        SDL_Log("Couldn't load texture [%s]: %s", (std::string(SDL_GetBasePath()) + "snake.png").c_str(), SDL_GetError());
        return SDL_APP_FAILURE;
    }

    SDL_Texture* ResizedTileMap = ScaleTexture(Renderer, GameObject.TileMap, TileScale);
    SDL_DestroyTexture(GameObject.TileMap);
    GameObject.TileMap = ResizedTileMap;


    GameObject.FruitsTileMap = IMG_LoadTexture(Renderer, (std::string(SDL_GetBasePath()) + "fruits.png").c_str());
    if (!GameObject.FruitsTileMap)
    {
        SDL_Log("Couldn't load texture [%s]: %s", (std::string(SDL_GetBasePath()) + "fruits.png").c_str(), SDL_GetError());
        return SDL_APP_FAILURE;
    }

#ifdef ANDROID
    ResizedTileMap = ScaleTexture(Renderer, GameObject.FruitsTileMap, 0.666666);
#else
    ResizedTileMap = ScaleTexture(Renderer, GameObject.FruitsTileMap, 0.333333);
#endif;
    SDL_DestroyTexture(GameObject.FruitsTileMap);
    GameObject.FruitsTileMap = ResizedTileMap;


    GameObject.Mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, nullptr);
    if (!GameObject.Mixer)
    {
        SDL_Log("Couldn't create mixer: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
    GameObject.Audio = MIX_LoadAudio(GameObject.Mixer, (std::string(SDL_GetBasePath()) + "LoopingSound.ogg").c_str(), true);
    if (!GameObject.Audio)
    {
        SDL_Log("Couldn't load audio [%s]: %s", (std::string(SDL_GetBasePath()) + "LoopingSound.ogg").c_str(), SDL_GetError());
        return SDL_APP_FAILURE;
    }
    GameObject.Track = MIX_CreateTrack(GameObject.Mixer);
    if (!GameObject.Track)
    {
        SDL_Log("Couldn't create audio track: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
    MIX_SetTrackAudio(GameObject.Track, GameObject.Audio);
    MIX_SetMixerGain(GameObject.Mixer, 60 / 100.0f);
    SDL_PropertiesID props = SDL_CreateProperties();
    SDL_SetNumberProperty(props, MIX_PROP_PLAY_LOOPS_NUMBER, -1);
    MIX_PlayTrack(GameObject.Track, props);
    SDL_DestroyProperties(props);

    GameObject.t = ((double)SDL_GetTicks()) / 1000.0;
    return SDL_APP_CONTINUE;
}

SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
{
    if (event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED || event->type == SDL_EVENT_WINDOW_RESIZED)
    {
        if (!GameObject.World)
        {
            SDL_GetWindowSize(Window, &GameObject.WindowWidth, &GameObject.WindowHeight);
            GameObject.World = new TWorld();
            if (!GameObject.World)
            {
                SDL_Log("Couldn't create world object");
                return SDL_APP_FAILURE;
            }
            GameObject.World->Reset();
        }
        return SDL_APP_CONTINUE;
    }

    SDL_AppResult Result = SDL_APP_CONTINUE;
    if (GameObject.World)
    {
        Result = GameObject.World->Snake->HandleEvent(event);
    }
    return Result;
}

void Update(float DeltaTime)
{
    GameObject.World->Update(DeltaTime);
}

SDL_AppResult SDL_AppIterate(void* appstate)
{
    double t = ((double)SDL_GetTicks()) / 1000.0;
    GameObject.DeltaTime = static_cast<float>(t - GameObject.t);

    Update(GameObject.DeltaTime);

    SDL_SetRenderDrawColorFloat(Renderer, 0.0f, 0.0f, 0.0f, SDL_ALPHA_OPAQUE_FLOAT);
    SDL_RenderClear(Renderer);

    //SDL_snprintf(GameObject.Text.data(), 254, "Witaj programisto C++! Aktualny czas: %.3f. FPS: %d", GameObject.t, static_cast<int>(GameObject.FrameCounter / GameObject.t));
    //DrawString(Renderer, GameObject.Text.c_str(), 10.0f, 10.0f);

    /*
    SDL_FRect r{ 0, 0, 200, 200 };
    SDL_SetRenderDrawColor(Renderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
    SDL_RenderFillRect(Renderer, &r);
    r = { 0, static_cast<float>(GameObject.WindowHeight - 200), 200, 200 };
    SDL_SetRenderDrawColor(Renderer, 0, 255, 0, SDL_ALPHA_OPAQUE);
    SDL_RenderFillRect(Renderer, &r);
    r = { static_cast<float>(GameObject.WindowWidth - 200), 0, 200, 200 };
    SDL_SetRenderDrawColor(Renderer, 0, 0, 255, SDL_ALPHA_OPAQUE);
    SDL_RenderFillRect(Renderer, &r);
    r = { static_cast<float>(GameObject.WindowWidth - 200), static_cast<float>(GameObject.WindowHeight - 200), 200, 200 };
    SDL_SetRenderDrawColor(Renderer, 255, 255, 0, SDL_ALPHA_OPAQUE);
    SDL_RenderFillRect(Renderer, &r);
    */

    GameObject.World->Render(Renderer);

    SDL_RenderPresent(Renderer);

    GameObject.FrameCounter += 1;
    GameObject.t = t;
    return SDL_APP_CONTINUE;
}

void SDL_AppQuit(void* appstate, SDL_AppResult result)
{
    if (GameObject.World)
    {
        delete GameObject.World;
    }
    if (GameObject.FruitsTileMap)
    {
        SDL_DestroyTexture(GameObject.FruitsTileMap);
    }
    if (GameObject.TileMap)
    {
        SDL_DestroyTexture(GameObject.TileMap);
    }
    if (Font)
    {
        TTF_CloseFont(Font);
    }
    if (Window)
    {
        SDL_DestroyWindow(Window);
    }
    if (Renderer)
    {
        SDL_DestroyRenderer(Renderer);
    }
    MIX_Quit();
    TTF_Quit();
    SDL_Quit();
}
