#include <cmath>
#include <cstddef>
#include <glviskit/glviskit.hpp>
#include <random>

auto main() -> int {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<float> dis(0.0F, 1.0F);
    auto rnf = [&]() -> float { return dis(gen); };

    // create a window 1
    auto window1 = glviskit::CreateWindow("Window1", 800, 600);

    // create a window 2
    auto render_list = glviskit::CreateRenderList();
    window1->AddRenderList(render_list);

    auto render_list_axes = glviskit::CreateRenderList();
    window1->AddRenderList(render_list_axes);

    render_list_axes->Size(5.0F);
    render_list_axes->Color({1.0F, 0.0F, 0.0F, 1.0F});
    render_list_axes->Line({0.0F, 0.0F, 0.0F}, {1.0F, 0.0F, 0.0F});
    render_list_axes->Color({0.0F, 1.0F, 0.0F, 1.0F});
    render_list_axes->Line({0.0F, 0.0F, 0.0F}, {0.0F, 1.0F, 0.0F});
    render_list_axes->Color({0.0F, 0.0F, 1.0F, 1.0F});
    render_list_axes->Line({0.0F, 0.0F, 0.0F}, {0.0F, 0.0F, 1.0F});

    auto camera = window1->GetCamera();
    camera->PerspectiveFov(60.0F, 60.0F);
    camera->SetPosition({0.0F, 0.0F, 0.0F});
    camera->SetRotation({0.0F, 0.0F, 0.0F});
    camera->SetPreserveAspectRatio(true);
    camera->SetDistance(10.0F);

    float angle = 0.0F;
    int frame_index = 0;

    size_t n = 100;
    auto x_stop = -10.0F;
    auto x_start = 10.0F;
    auto y_stop = -10.0F;
    auto y_start = 10.0F;

    std::vector<float> xs;
    xs.reserve(n);
    std::vector<float> ys;
    ys.reserve(n);

    for (int i = 0; i < n; i++) {
        xs.push_back(x_start +
                     ((x_stop - x_start) *
                      (static_cast<float>(i) / static_cast<float>(n - 1))));
        ys.push_back(y_start +
                     ((y_stop - y_start) *
                      (static_cast<float>(i) / static_cast<float>(n - 1))));
    }

    std::vector<float> zs;
    zs.reserve(n * n);

    while (glviskit::Loop()) {
        const float curr_time = glviskit::GetTimeSeconds();

        frame_index++;
        angle += 0.005F;
        camera->SetRotation({-0.5F, angle, 0.0F});

        render_list->Clear();

        render_list->Color({0.2F, 0.7F, 1.0F, 1.0F});
        render_list->Size(2.0F);

        // compute zs
        zs.clear();
        for (auto x : xs) {
            for (auto y : ys) {
                float z = std::sin(x - curr_time) * std::cos(y - curr_time);
                zs.push_back(z);
            }
        }

        // horizontal lines
        auto path = render_list->PathBegin();
        for (size_t i = 0; i < n; i++) {
            for (size_t j = 0; j < n; j++) {
                path->LineTo({xs[j], zs[(i * n) + j], ys[i]});
            }
            path->LineEnd();
        }

        // vertical line
        for (size_t j = 0; j < n; j++) {
            for (size_t i = 0; i < n; i++) {
                path->LineTo({xs[j], zs[(i * n) + j], ys[i]});
            }
            path->LineEnd();
        }
    }
    return 0;
}