#include "McpScreen.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <esp_log.h>
#include <esp_heap_caps.h>
#include <tt_lvgl.h>
#include <tt_lvgl_toolbar.h>
#include <tt_wifi.h>

static const char* TAG = "McpScreen";

static void set_label_text_locked(lv_obj_t* label, const char* text) {
    if (label != NULL && lv_obj_is_valid(label)) {
        lv_label_set_text(label, text);
    }
}

void mcp_ui_set_server_status(McpScreenState* state, const char* status) {
    if (state == NULL || !state->visible) {
        return;
    }

    if (tt_lvgl_lock(pdMS_TO_TICKS(1000))) {
        if (state->visible) {
            set_label_text_locked(state->server_label, status);
        }
        tt_lvgl_unlock();
    }
}

void mcp_ui_set_last_tool(McpScreenState* state, const char* tool) {
    if (state == NULL || !state->visible) {
        return;
    }

    if (tt_lvgl_lock(pdMS_TO_TICKS(1000))) {
        if (state->visible && state->tool_label != NULL && lv_obj_is_valid(state->tool_label)) {
            lv_label_set_text_fmt(state->tool_label, "Last: %s", tool);
        }
        tt_lvgl_unlock();
    }
}

bool mcp_ui_clear(McpScreenState* state, int color) {
    if (state == NULL || !state->visible || state->framebuffer == NULL) {
        return false;
    }

    bool success = false;
    if (tt_lvgl_lock(pdMS_TO_TICKS(1500))) {
        if (state->visible && state->draw_area != NULL && lv_obj_is_valid(state->draw_area)) {
            lv_obj_clean(state->draw_area);
            uint16_t fill = color == 1 ? 0x0000 : 0xFFFF;
            size_t pixel_count = (size_t)state->draw_width * state->draw_height;
            for (size_t i = 0; i < pixel_count; ++i) {
                state->framebuffer[i] = fill;
            }
            lv_obj_invalidate(state->draw_area);
            state->draw_color = color;
            state->override_active = true;
            success = true;
        }
        tt_lvgl_unlock();
    }
    return success;
}

bool mcp_ui_draw_text(
    McpScreenState* state,
    const char* text,
    int x,
    int y,
    int size
) {
    if (state == NULL || text == NULL || !state->visible) {
        return false;
    }

    bool success = false;
    if (tt_lvgl_lock(pdMS_TO_TICKS(1500))) {
        if (state->visible && state->draw_area != NULL && lv_obj_is_valid(state->draw_area)) {
            int max_x = state->draw_width > 0 ? state->draw_width - 1 : 0;
            int max_y = state->draw_height > 0 ? state->draw_height - 1 : 0;
            if (x < 0) x = 0;
            if (y < 0) y = 0;
            if (x > max_x) x = max_x;
            if (y > max_y) y = max_y;

            lv_obj_t* label = lv_label_create(state->draw_area);
            lv_label_set_text(label, text);
            lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
            lv_obj_set_width(label, LV_MAX(1, state->draw_width - x));
            lv_obj_set_pos(label, x, y);

            lv_obj_set_style_text_color(
                label,
                state->draw_color == 0 ? lv_color_black() : lv_color_white(),
                LV_PART_MAIN
            );

#if LV_FONT_MONTSERRAT_24
            if (size >= 2) {
                lv_obj_set_style_text_font(label, &lv_font_montserrat_24, LV_PART_MAIN);
            }
#else
            (void)size;
#endif

            state->override_active = true;
            success = true;
        }
        tt_lvgl_unlock();
    }
    return success;
}

static void* create_data(void) {
    McpScreenState* state = calloc(1, sizeof(McpScreenState));
    if (state != NULL) {
        state->http_socket = -1;
        state->client_socket = -1;
        state->discovery_socket = -1;
    }
    return state;
}

static void destroy_data(void* data) {
    McpScreenState* state = data;
    if (state != NULL && state->framebuffer != NULL) {
        heap_caps_free(state->framebuffer);
    }
    free(state);
}

static void on_create(AppHandle app, void* data) {
    McpScreenState* state = data;
    state->app = app;
}

static void on_destroy(AppHandle app, void* data) {
    (void)app;
    mcp_services_stop((McpScreenState*)data);
}

static void on_show(AppHandle app, void* data, lv_obj_t* parent) {
    McpScreenState* state = data;
    ESP_LOGI(TAG, "onShow: starting foreground UI and MCP service");
    state->visible = true;

    lv_obj_remove_flag(parent, LV_OBJ_FLAG_SCROLLABLE);
    lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
    lv_obj_set_style_pad_all(parent, 0, LV_PART_MAIN);
    lv_obj_set_style_pad_row(parent, 0, LV_PART_MAIN);

    lv_obj_t* toolbar = tt_lvgl_toolbar_create_for_app(parent, app);
    lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0);

    state->server_label = lv_label_create(toolbar);
    lv_label_set_text(state->server_label, "MCP starting");
    lv_obj_set_style_text_color(
        state->server_label,
        lv_palette_main(LV_PALETTE_ORANGE),
        LV_PART_MAIN
    );

    state->tool_label = lv_label_create(toolbar);
    lv_label_set_text(state->tool_label, "Last: none");

    if (!mcp_services_start(state)) {
        ESP_LOGE(TAG, "Failed to start foreground MCP service");
        lv_label_set_text(state->server_label, "MCP start failed");
        lv_obj_set_style_text_color(
            state->server_label,
            lv_palette_main(LV_PALETTE_RED),
            LV_PART_MAIN
        );
    }

    state->draw_area = lv_canvas_create(parent);
    lv_obj_set_width(state->draw_area, LV_PCT(100));
    lv_obj_set_flex_grow(state->draw_area, 1);
    lv_obj_set_style_radius(state->draw_area, 0, LV_PART_MAIN);
    lv_obj_set_style_border_width(state->draw_area, 0, LV_PART_MAIN);
    lv_obj_set_style_pad_all(state->draw_area, 0, LV_PART_MAIN);
    lv_obj_remove_flag(state->draw_area, LV_OBJ_FLAG_SCROLLABLE);

    lv_display_t* display = lv_obj_get_display(parent);
    state->display_width = lv_display_get_horizontal_resolution(display);
    state->display_height = lv_display_get_vertical_resolution(display);

    lv_obj_update_layout(parent);
    state->draw_width = lv_obj_get_content_width(state->draw_area);
    state->draw_height = lv_obj_get_content_height(state->draw_area);

    size_t required_size = (size_t)state->draw_width * state->draw_height * sizeof(uint16_t);
    if (state->framebuffer == NULL || state->framebuffer_size != required_size) {
        if (state->framebuffer != NULL) {
            heap_caps_free(state->framebuffer);
            state->framebuffer = NULL;
        }
        state->framebuffer = heap_caps_malloc(required_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
        if (state->framebuffer == NULL) {
            state->framebuffer = heap_caps_malloc(required_size, MALLOC_CAP_8BIT);
        }
        state->framebuffer_size = state->framebuffer == NULL ? 0 : required_size;
    }

    if (state->framebuffer == NULL) {
        ESP_LOGE(TAG, "Failed to allocate %u-byte framebuffer", (unsigned)required_size);
        lv_obj_t* error = lv_label_create(state->draw_area);
        lv_label_set_text(error, "Framebuffer allocation failed");
        lv_obj_center(error);
        return;
    }

    lv_canvas_set_buffer(
        state->draw_area,
        state->framebuffer,
        state->draw_width,
        state->draw_height,
        LV_COLOR_FORMAT_RGB565
    );

    if (!state->override_active) {
        for (size_t i = 0; i < (size_t)state->draw_width * state->draw_height; ++i) {
            state->framebuffer[i] = 0x10C3;
        }
        state->draw_color = 1;

        lv_obj_t* title = lv_label_create(state->draw_area);
        lv_label_set_text(title, "MCP Screen");
        lv_obj_set_style_text_color(title, lv_color_white(), LV_PART_MAIN);
#if LV_FONT_MONTSERRAT_24
        lv_obj_set_style_text_font(title, &lv_font_montserrat_24, LV_PART_MAIN);
#endif
        lv_obj_align(title, LV_ALIGN_CENTER, 0, -55);

        lv_obj_t* dimensions = lv_label_create(state->draw_area);
        lv_label_set_text_fmt(
            dimensions,
            "%ux%u display\nHTTP :80\nDiscovery: bridge subnet scan",
            state->display_width,
            state->display_height
        );
        lv_obj_set_style_text_align(dimensions, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN);
        lv_obj_set_style_text_color(dimensions, lv_palette_lighten(LV_PALETTE_BLUE, 3), LV_PART_MAIN);
        lv_obj_align(dimensions, LV_ALIGN_CENTER, 0, 0);

        lv_obj_t* wifi = lv_label_create(state->draw_area);
        lv_label_set_text_fmt(
            wifi,
            "Wi-Fi: %s",
            tt_wifi_radio_state_to_string(tt_wifi_get_radio_state())
        );
        lv_obj_set_style_text_color(wifi, lv_color_white(), LV_PART_MAIN);
        lv_obj_align(wifi, LV_ALIGN_CENTER, 0, 48);
    }

}

static void on_hide(AppHandle app, void* data) {
    (void)app;
    McpScreenState* state = data;
    ESP_LOGI(TAG, "onHide: stopping foreground MCP service");
    state->visible = false;
    mcp_services_hide(state);
    state->draw_area = NULL;
    state->server_label = NULL;
    state->tool_label = NULL;
}

int main(int argc, char* argv[]) {
    (void)argc;
    (void)argv;
    tt_app_register((AppRegistration) {
        .createData = create_data,
        .destroyData = destroy_data,
        .onCreate = on_create,
        .onDestroy = on_destroy,
        .onShow = on_show,
        .onHide = on_hide
    });
    return 0;
}
