/*
 * DWN - Desktop Window Manager
 * Tiling Layout Plugin (Built-in)
 */

#include "plugins/layout_plugin.h"
#include "core/wm_client.h"
#include "util.h"

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

/*==============================================================================
 * Tiling Layout State
 *============================================================================*/

typedef struct {
    int dummy;  /* Placeholder for future state */
} TilingState;

/*==============================================================================
 * Tiling Layout Interface
 *============================================================================*/

static bool tiling_init(LayoutPlugin *plugin) {
    LOG_INFO("Tiling layout initialized");
    (void)plugin;
    return true;
}

static void tiling_shutdown(LayoutPlugin *plugin) {
    LOG_INFO("Tiling layout shutdown");
    (void)plugin;
}

static WmLayoutState* tiling_state_create(LayoutPlugin *plugin, WmWorkspaceId workspace) {
    (void)plugin;
    (void)workspace;
    
    /* Layout manager allocates WmLayoutState, we just return our plugin data */
    TilingState *ts = calloc(1, sizeof(TilingState));
    return (WmLayoutState*)ts;  /* Cast to opaque type */
}

static void tiling_state_destroy(LayoutPlugin *plugin, WmLayoutState *state) {
    (void)plugin;
    free(state);  /* state is actually TilingState* */
}

static void tiling_state_reset(LayoutPlugin *plugin, WmLayoutState *state) {
    (void)plugin;
    
    if (state) {
        memset(state, 0, sizeof(TilingState));
    }
}

/*==============================================================================
 * Tiling Layout Calculation
 *============================================================================*/

static bool tiling_arrange(LayoutPlugin *plugin, LayoutContext *ctx,
                            AbstractClient **clients, int num_clients,
                            WmLayoutGeometry *geometries) {
    (void)plugin;
    (void)clients;
    
    if (num_clients == 0) return true;
    
    WmLayoutWorkArea *wa = &ctx->work_area;
    int gap = ctx->gap;
    
    /* Calculate effective work area with padding */
    int wx = wa->x + wa->padding_left;
    int wy = wa->y + wa->padding_top;
    int ww = wa->width - wa->padding_left - wa->padding_right;
    int wh = wa->height - wa->padding_top - wa->padding_bottom;
    
    /* Apply gap to work area */
    wx += gap;
    wy += gap;
    ww -= gap * 2;
    wh -= gap * 2;
    
    if (num_clients == 1) {
        /* Single client takes full area */
        geometries[0].x = wx;
        geometries[0].y = wy;
        geometries[0].width = ww;
        geometries[0].height = wh;
        geometries[0].floating = false;
        return true;
    }
    
    /* Calculate master area */
    int master_count = ctx->master_count_target;
    if (master_count < 1) master_count = 1;
    if (master_count > num_clients) master_count = num_clients;
    
    int stack_count = num_clients - master_count;
    
    /* Calculate master width based on ratio */
    int master_w = (stack_count > 0) ? (int)(ww * ctx->master_ratio) : ww;
    int stack_w = ww - master_w;
    
    /* Adjust for gap */
    if (stack_count > 0) {
        master_w -= gap / 2;
        stack_w -= gap / 2;
    }
    
    /* Arrange master clients vertically */
    int master_h = wh / master_count;
    int master_h_remainder = wh % master_count;
    
    for (int i = 0; i < master_count; i++) {
        geometries[i].x = wx;
        geometries[i].y = wy + i * master_h + (i < master_h_remainder ? i : master_h_remainder);
        geometries[i].width = master_w;
        geometries[i].height = master_h + (i < master_h_remainder ? 1 : 0);
        geometries[i].floating = false;
        
        /* Apply gap */
        if (i > 0) {
            geometries[i].y += gap;
            geometries[i].height -= gap;
        }
        if (i < master_count - 1) {
            geometries[i].height -= gap;
        }
    }
    
    /* Arrange stack clients vertically */
    if (stack_count > 0) {
        int stack_x = wx + master_w + gap;
        int stack_h = wh / stack_count;
        int stack_h_remainder = wh % stack_count;
        
        for (int i = 0; i < stack_count; i++) {
            int idx = master_count + i;
            geometries[idx].x = stack_x;
            geometries[idx].y = wy + i * stack_h + (i < stack_h_remainder ? i : stack_h_remainder);
            geometries[idx].width = stack_w;
            geometries[idx].height = stack_h + (i < stack_h_remainder ? 1 : 0);
            geometries[idx].floating = false;
            
            /* Apply gap */
            if (i > 0) {
                geometries[idx].y += gap;
                geometries[idx].height -= gap;
            }
            if (i < stack_count - 1) {
                geometries[idx].height -= gap;
            }
        }
    }
    
    return true;
}

/*==============================================================================
 * Layout Manipulation
 *============================================================================*/

static void tiling_inc_master(LayoutPlugin *plugin, LayoutContext *ctx, int delta) {
    (void)plugin;
    
    int new_count = ctx->master_count_target + delta;
    if (new_count < 1) new_count = 1;
    if (new_count > ctx->client_count) new_count = ctx->client_count;
    
    ctx->master_count_target = new_count;
}

static void tiling_set_master_ratio(LayoutPlugin *plugin, LayoutContext *ctx, float ratio) {
    (void)plugin;
    
    if (ratio < 0.1f) ratio = 0.1f;
    if (ratio > 0.9f) ratio = 0.9f;
    
    ctx->master_ratio = ratio;
}

static void tiling_set_master_count(LayoutPlugin *plugin, LayoutContext *ctx, int count) {
    (void)plugin;
    
    if (count < 1) count = 1;
    if (count > ctx->client_count) count = ctx->client_count;
    
    ctx->master_count_target = count;
}

static void tiling_swap_master(LayoutPlugin *plugin, LayoutContext *ctx) {
    (void)plugin;
    (void)ctx;
}

static void tiling_rotate(LayoutPlugin *plugin, LayoutContext *ctx, bool clockwise) {
    (void)plugin;
    (void)ctx;
    (void)clockwise;
}

static void tiling_resize_master(LayoutPlugin *plugin, LayoutContext *ctx,
                                  int x, int y, int *new_master_count, float *new_ratio) {
    (void)plugin;
    (void)x;
    (void)y;
    
    *new_master_count = ctx->master_count_target;
    *new_ratio = ctx->master_ratio;
}

/*==============================================================================
 * Layout Configuration Parameters
 *============================================================================*/

static WmLayoutParameter tiling_parameters[] = {
    {
        .name = "master_ratio",
        .description = "Ratio of screen width for master area",
        .type = WM_LAYOUT_PARAM_FLOAT,
        .default_value.float_value = 0.5f
    },
    {
        .name = "master_count",
        .description = "Number of clients in master area",
        .type = WM_LAYOUT_PARAM_INT,
        .default_value.int_value = 1
    },
    {
        .name = "gap",
        .description = "Gap between windows in pixels",
        .type = WM_LAYOUT_PARAM_INT,
        .default_value.int_value = 0
    }
};

/*==============================================================================
 * Layout Plugin Interface
 *============================================================================*/

static LayoutPluginInterface tiling_interface = {
    .api_version = WM_LAYOUT_PLUGIN_API_VERSION,
    .name = "tiling",
    .description = "Classic tiling layout with master and stack areas",
    .author = "DWN",
    .version = "1.0",
    
    .parameters = tiling_parameters,
    .num_parameters = sizeof(tiling_parameters) / sizeof(tiling_parameters[0]),
    
    .init = tiling_init,
    .shutdown = tiling_shutdown,
    
    .state_create = tiling_state_create,
    .state_destroy = tiling_state_destroy,
    .state_reset = tiling_state_reset,
    
    .config_parse = NULL,
    .config_apply = NULL,
    
    .arrange = tiling_arrange,
    
    .client_added = NULL,
    .client_removed = NULL,
    .client_floating_changed = NULL,
    
    .inc_master = tiling_inc_master,
    .set_master_ratio = tiling_set_master_ratio,
    .set_master_count = tiling_set_master_count,
    .swap_master = tiling_swap_master,
    .rotate = tiling_rotate,
    .resize_master = tiling_resize_master
};

/*==============================================================================
 * Exported Interface
 *============================================================================*/

const LayoutPluginInterface* wm_layout_tiling_get_interface(void) {
    return &tiling_interface;
}

/* Register as a built-in layout */
WM_LAYOUT_REGISTER(tiling, tiling_interface)
