const std = @import("std");
const builtin = @import("builtin");

const jetzig = @import("jetzig");
const zmd = @import("zmd");

pub const routes = @import("routes");
pub const static = @import("static");

pub const jetzig_options = struct {
    pub const middleware: []const type = &.{};

    pub const max_bytes_request_body: usize = std.math.pow(usize, 2, 16);
    pub const max_bytes_public_content: usize = std.math.pow(usize, 2, 20);
    pub const max_bytes_static_content: usize = std.math.pow(usize, 2, 18);
    pub const max_bytes_header_name: u16 = 40;
    pub const max_multipart_form_fields: usize = 20;
    pub const log_message_buffer_len: usize = 4096;
    pub const max_log_pool_len: usize = 256;
    pub const thread_count: ?u16 = null;
    pub const worker_count: u16 = 4;
    pub const max_connections: u16 = 512;
    pub const buffer_size: usize = 64 * 1024;
    pub const arena_size: usize = 1024 * 1024;
    pub const public_content_path = "public";
    pub const http_buffer_size: usize = std.math.pow(usize, 2, 16);
    pub const job_worker_threads: usize = 4;
    pub const job_worker_sleep_interval_ms: usize = 10;

    pub const Schema = @import("Schema");

    pub const cookies: jetzig.http.Cookies.CookieOptions = switch (jetzig.environment) {
        .development, .testing => .{
            .domain = "localhost",
            .path = "/",
        },
        .production => .{
            .same_site = .strict,
            .secure = true,
            .http_only = true,
            .path = "/",
        },
    };

    pub const store: jetzig.kv.Store.Options = .{
        .backend = .memory,
    };
    pub const job_queue: jetzig.kv.Store.Options = .{
        .backend = .memory,
    };
    pub const cache: jetzig.kv.Store.Options = .{
        .backend = .memory,
    };
    pub const force_development_email_delivery = false;

    pub const markdown_fragments = struct {
        pub const root = .{
            "<div class='p-5'>",
            "</div>",
        };
        pub const h1 = .{
            "<h1 class='text-2xl mb-3 text-green font-bold'>",
            "</h1>",
        };
        pub const h2 = .{
            "<h2 class='text-xl mb-3 font-bold'>",
            "</h2>",
        };
        pub const h3 = .{
            "<h3 class='text-lg mb-3 font-bold'>",
            "</h3>",
        };
        pub const paragraph = .{
            "<p class='p-3'>",
            "</p>",
        };
        pub const code = .{
            "<span class='font-mono bg-gray-900 p-2 text-white'>",
            "</span>",
        };

        pub const unordered_list = .{
            "<ul class='list-disc ms-8 leading-8'>",
            "</ul>",
        };

        pub const ordered_list = .{
            "<ul class='list-decimal ms-8 leading-8'>",
            "</ul>",
        };

        pub fn block(allocator: std.mem.Allocator, node: zmd.Node) ![]const u8 {
            return try std.fmt.allocPrint(allocator,
                \\<pre class="w-1/2 font-mono mt-4 ms-3 bg-gray-900 p-2 text-white"><code class="language-{?s}">{s}</code></pre>
            , .{ node.meta, node.content });
        }

        pub fn link(allocator: std.mem.Allocator, node: zmd.Node) ![]const u8 {
            return try std.fmt.allocPrint(allocator,
                \\<a class="underline decoration-sky-500" href="{0s}" title={1s}>{1s}</a>
            , .{ node.href.?, node.title.? });
        }
    };
};

pub fn init(app: *jetzig.App) !void {
    app.route(.GET, "/rss.xml", @import("app/views/rss.zig"), .index);
    app.route(.GET, "/blogs/:id/edit", @import("app/views/blogs.zig"), .edit);
    app.route(.POST, "/blogs/:id/edit", @import("app/views/blogs.zig"), .edit);
    app.route(.GET, "/tags/:id/edit", @import("app/views/tags.zig"), .edit);
    app.route(.POST, "/tags/:id/edit", @import("app/views/tags.zig"), .edit);
    app.route(.GET, "/blogs/tags/:id", @import("app/views/tags.zig"), .get);
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = if (builtin.mode == .Debug) gpa.allocator() else std.heap.c_allocator;
    defer if (builtin.mode == .Debug) std.debug.assert(gpa.deinit() == .ok);

    var app = try jetzig.init(allocator);
    defer app.deinit();

    try app.start(routes, .{});
}
