/*
    * login_render.cpp
    * Layout and drawing for the MontaukOS login screen
    * Copyright (c) 2026 Daniel Hammer
*/

#include "login.hpp"

using namespace gui;

static Rect offset_rect(Rect rect, int dx, int dy) {
    rect.x += dx;
    rect.y += dy;
    return rect;
}

LoginLayout layout_login_screen(LoginState* ls) {
    LoginLayout lo = {};
    int sfh = system_font_height();

    lo.window_title = ls->mode == MODE_FIRST_BOOT ? "MontaukOS Setup" : "MontaukOS";
    lo.heading = ls->mode == MODE_FIRST_BOOT ? "Create Administrator Account" : "Log In";
    lo.subtitle = ls->mode == MODE_FIRST_BOOT
        ? "Create the first administrator account."
        : "Sign in to continue to the desktop.";
    lo.submit_label = ls->mode == MODE_FIRST_BOOT ? "Create Account" : "Log In";

    lo.content_x = CONTENT_PAD_X;
    lo.content_w = CARD_W - CONTENT_PAD_X * 2;

    int y = TITLEBAR_H + CONTENT_TOP_PAD;
    lo.heading_y = y;
    y += sfh + 6;
    lo.subtitle_y = y;
    y += sfh + 18;

    lo.username_field = {lo.content_x, y + sfh + LABEL_GAP, lo.content_w, FIELD_H};
    y = lo.username_field.y + FIELD_H + FIELD_GAP;

    if (ls->mode == MODE_FIRST_BOOT) {
        lo.display_name_field = {lo.content_x, y + sfh + LABEL_GAP, lo.content_w, FIELD_H};
        y = lo.display_name_field.y + FIELD_H + FIELD_GAP;

        lo.password_field = {lo.content_x, y + sfh + LABEL_GAP, lo.content_w, FIELD_H};
        y = lo.password_field.y + FIELD_H + FIELD_GAP;

        lo.confirm_field = {lo.content_x, y + sfh + LABEL_GAP, lo.content_w, FIELD_H};
        y = lo.confirm_field.y + FIELD_H + FIELD_GAP;
    } else {
        lo.password_field = {lo.content_x, y + sfh + LABEL_GAP, lo.content_w, FIELD_H};
        y = lo.password_field.y + FIELD_H + FIELD_GAP;
    }

    // Session selector (login mode only): a "Session" label above two radio
    // options that pick the desktop or the full-screen console.
    if (ls->mode == MODE_LOGIN) {
        lo.session_label_y = y;
        int ry = y + sfh + LABEL_GAP;
        int radio_h = 22;
        int half = lo.content_w / 2;
        lo.desktop_radio = {lo.content_x, ry, half, radio_h};
        lo.console_radio = {lo.content_x + half, ry, half, radio_h};
        y = ry + radio_h + FIELD_GAP;
    } else {
        lo.session_label_y = -1;
    }

    if (ls->show_error) {
        lo.error_y = y;
        y += sfh + 12;
    } else {
        lo.error_y = -1;
    }

    int footer_y = y + BODY_BOTTOM_PAD;
    int card_h = footer_y + FOOTER_H;
    int card_x = (ls->screen_w - CARD_W) / 2;
    int card_y = (ls->screen_h - card_h) / 2;

    lo.card = {card_x, card_y, CARD_W, card_h};
    lo.titlebar = {card_x, card_y, CARD_W, TITLEBAR_H};
    lo.footer = {card_x, card_y + footer_y, CARD_W, FOOTER_H};

    int submit_w = text_width(lo.submit_label) + 32;
    if (submit_w < 100) submit_w = 100;
    int footer_btn_y = footer_y + (FOOTER_H - BTN_H) / 2;
    lo.shutdown_button = {FOOTER_PAD, footer_btn_y, POWER_BTN_W, BTN_H};
    lo.reboot_button = {FOOTER_PAD + POWER_BTN_W + POWER_BTN_GAP, footer_btn_y, POWER_BTN_W, BTN_H};
    lo.submit_button = {CARD_W - FOOTER_PAD - submit_w, footer_btn_y, submit_w, BTN_H};

    lo.username_field = offset_rect(lo.username_field, card_x, card_y);
    lo.display_name_field = offset_rect(lo.display_name_field, card_x, card_y);
    lo.password_field = offset_rect(lo.password_field, card_x, card_y);
    lo.confirm_field = offset_rect(lo.confirm_field, card_x, card_y);
    lo.shutdown_button = offset_rect(lo.shutdown_button, card_x, card_y);
    lo.reboot_button = offset_rect(lo.reboot_button, card_x, card_y);
    lo.submit_button = offset_rect(lo.submit_button, card_x, card_y);
    lo.desktop_radio = offset_rect(lo.desktop_radio, card_x, card_y);
    lo.console_radio = offset_rect(lo.console_radio, card_x, card_y);

    lo.content_x += card_x;
    lo.heading_y += card_y;
    lo.subtitle_y += card_y;
    if (lo.error_y >= 0) lo.error_y += card_y;
    if (lo.session_label_y >= 0) lo.session_label_y += card_y;
    return lo;
}

void draw_login_screen(LoginState* ls) {
    Framebuffer& fb = ls->fb;
    LoginLayout lo = layout_login_screen(ls);
    const mtk::Theme& th = ls->theme;
    int sfh = system_font_height();
    int sw = ls->screen_w;
    int sh = ls->screen_h;

    // MTK widgets draw through a Canvas, which assumes a tightly packed pixel
    // buffer (pitch == width*4). Draw straight into the framebuffer back buffer
    // when its pitch is already packed; otherwise compose into the packed
    // scratch buffer and copy across (handling pitch) before flipping.
    bool packed = fb.pitch() == sw * (int)sizeof(uint32_t);
    uint32_t* target = packed ? fb.buffer() : ls->compose;
    if (!target) return;
    Canvas c(target, sw, sh);

    // ==== Background ====
    if (ls->has_wallpaper && ls->bg_wallpaper) {
        montauk::memcpy(target, ls->bg_wallpaper,
                        (uint64_t)sw * sh * sizeof(uint32_t));
    } else {
        c.fill(BG_COLOR);
    }

    // ==== Card ====
    int so = 4; // drop-shadow offset
    c.fill_rect_alpha(lo.card.x + so, lo.card.y + lo.card.h, lo.card.w, so, colors::SHADOW);
    c.fill_rect_alpha(lo.card.x + lo.card.w, lo.card.y + so, so, lo.card.h, colors::SHADOW);
    c.fill_rect_alpha(lo.card.x + lo.card.w, lo.card.y + lo.card.h, so, so, colors::SHADOW);

    c.fill_rect(lo.card.x, lo.card.y, lo.card.w, lo.card.h, CARD_BG);
    c.fill_rect(lo.titlebar.x, lo.titlebar.y, lo.titlebar.w, lo.titlebar.h, TITLEBAR_BG);
    c.fill_rect(lo.footer.x, lo.footer.y, lo.footer.w, lo.footer.h, FOOTER_BG);
    c.rect(lo.card.x, lo.card.y, lo.card.w, lo.card.h, CARD_BORDER);
    c.hline(lo.titlebar.x, lo.titlebar.y + lo.titlebar.h - 1, lo.titlebar.w, CARD_BORDER);
    c.hline(lo.footer.x, lo.footer.y, lo.footer.w, CARD_BORDER);

    int window_tw = text_width(lo.window_title);
    c.text(lo.titlebar.x + (lo.titlebar.w - window_tw) / 2,
           lo.titlebar.y + (TITLEBAR_H - sfh) / 2, lo.window_title, th.text);
    c.text(lo.content_x, lo.heading_y, lo.heading, th.text);
    c.text(lo.content_x, lo.subtitle_y, lo.subtitle, th.text_subtle);

    // ==== Fields ====
    auto field = [&](const Rect& r, const char* label, const char* val,
                     mtk::TextInputState& st, bool masked, bool active) {
        c.text(r.x, r.y - LABEL_GAP - sfh, label, th.text_muted);
        mtk::draw_text_field(c, r, val, st.cursor, active, masked, th,
                             active ? st.selection_anchor : -1);
    };

    field(lo.username_field, "Username", ls->username, ls->username_input,
          false, ls->active_field == 0);
    if (ls->mode == MODE_FIRST_BOOT) {
        field(lo.display_name_field, "Display Name", ls->display_name,
              ls->display_name_input, false, ls->active_field == 1);
        field(lo.password_field, "Password", ls->password,
              ls->password_input, true, ls->active_field == 2);
        field(lo.confirm_field, "Confirm Password", ls->confirm,
              ls->confirm_input, true, ls->active_field == 3);
    } else {
        field(lo.password_field, "Password", ls->password,
              ls->password_input, true, ls->active_field == 1);
    }

    // ==== Session selector ====
    if (ls->mode == MODE_LOGIN && lo.session_label_y >= 0) {
        c.text(lo.content_x, lo.session_label_y, "Session", th.text_muted);
        mtk::draw_radio(c, lo.desktop_radio, "Desktop",
                        ls->session_mode == SESSION_DESKTOP, th);
        mtk::draw_radio(c, lo.console_radio, "Console",
                        ls->session_mode == SESSION_CONSOLE, th);
    }

    if (ls->show_error && lo.error_y >= 0)
        c.text(lo.content_x, lo.error_y, ls->error_msg, th.danger);

    // ==== Buttons ====
    auto btn = [&](const Rect& r) {
        return mtk::widget_state(false, r.contains(ls->mouse.x, ls->mouse.y), true);
    };
    mtk::draw_button(c, lo.shutdown_button, "Shut Down", mtk::BUTTON_SECONDARY,
                     btn(lo.shutdown_button), th);
    mtk::draw_button(c, lo.reboot_button, "Restart", mtk::BUTTON_SECONDARY,
                     btn(lo.reboot_button), th);
    mtk::draw_button(c, lo.submit_button, lo.submit_label, mtk::BUTTON_PRIMARY,
                     btn(lo.submit_button), th);

    // ==== Present ====
    if (!packed) fb.copy_from(ls->compose, sw * (int)sizeof(uint32_t));
    draw_cursor(fb, ls->mouse.x, ls->mouse.y);
    fb.flip();
}
