/**
 * aviation_queue.c — Queue manager implementation.
 *
 * Fixed-capacity array for items. Fisher-Yates shuffle with
 * current-item-first guarantee. Index adjustment on mutation.
 */

#include "aviation_queue.h"
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* ─── Internal state ──────────────────────────────────────────────── */

struct AviationQueueManager {
    AviationMediaItem items[AVIATION_MAX_QUEUE_SIZE];
    int count;
    int current_index;

    /* Shuffle */
    bool shuffle_enabled;
    int shuffle_order[AVIATION_MAX_QUEUE_SIZE];
    int shuffle_count;

    /* Repeat */
    AviationRepeatMode repeat_mode;

    /* RNG seeded flag */
    bool rng_seeded;
};

/* ─── Internal helpers ────────────────────────────────────────────── */

static void ensure_rng_seeded(AviationQueueManager *q) {
    if (!q->rng_seeded) {
        srand((unsigned int)time(NULL));
        q->rng_seeded = true;
    }
}

/**
 * Fisher-Yates shuffle of indices [0..count-1].
 * Guarantees current_index is first in the shuffle order.
 */
static void rebuild_shuffle_order(AviationQueueManager *q) {
    if (!q->shuffle_enabled || q->count == 0) {
        q->shuffle_count = 0;
        return;
    }

    ensure_rng_seeded(q);

    q->shuffle_count = q->count;

    /* Initialize with sequential indices */
    for (int i = 0; i < q->count; i++) {
        q->shuffle_order[i] = i;
    }

    /* Fisher-Yates shuffle */
    for (int i = q->count - 1; i > 0; i--) {
        int j = rand() % (i + 1);
        int tmp = q->shuffle_order[i];
        q->shuffle_order[i] = q->shuffle_order[j];
        q->shuffle_order[j] = tmp;
    }

    /* Move current_index to position 0 in shuffle order */
    if (q->current_index >= 0 && q->current_index < q->count) {
        for (int i = 0; i < q->shuffle_count; i++) {
            if (q->shuffle_order[i] == q->current_index) {
                /* Swap with position 0 */
                int tmp = q->shuffle_order[0];
                q->shuffle_order[0] = q->shuffle_order[i];
                q->shuffle_order[i] = tmp;
                break;
            }
        }
    }
}

/** Find the position of current_index within the shuffle order. Returns -1 if not found. */
static int find_shuffle_position(const AviationQueueManager *q, int index) {
    for (int i = 0; i < q->shuffle_count; i++) {
        if (q->shuffle_order[i] == index) {
            return i;
        }
    }
    return -1;
}

/* ─── Lifecycle ───────────────────────────────────────────────────── */

AviationQueueManager *aviation_queue_create(void) {
    AviationQueueManager *q = (AviationQueueManager *)calloc(1, sizeof(AviationQueueManager));
    if (!q)
        return NULL;
    q->current_index = -1;
    q->repeat_mode = AVIATION_REPEAT_OFF;
    return q;
}

void aviation_queue_destroy(AviationQueueManager *queue) { free(queue); }

/* ─── Queue mutation ──────────────────────────────────────────────── */

int aviation_queue_set(AviationQueueManager *q, const AviationMediaItem *items, int count) {
    if (!q)
        return -1;
    if (count < 0 || count > AVIATION_MAX_QUEUE_SIZE)
        return -1;

    if (count > 0 && items) {
        memcpy(q->items, items, (size_t)count * sizeof(AviationMediaItem));
    }
    q->count = count;
    q->current_index = -1;
    rebuild_shuffle_order(q);
    return 0;
}

int aviation_queue_add(AviationQueueManager *q, const AviationMediaItem *item) {
    if (!q || !item)
        return -1;
    if (q->count >= AVIATION_MAX_QUEUE_SIZE)
        return -1;

    q->items[q->count] = *item;
    q->count++;
    rebuild_shuffle_order(q);
    return 0;
}

int aviation_queue_insert_after(AviationQueueManager *q, const AviationMediaItem *item, int after_index) {
    if (!q || !item)
        return -1;
    if (after_index < 0 || after_index >= q->count)
        return -1;
    if (q->count >= AVIATION_MAX_QUEUE_SIZE)
        return -1;

    int insert_at = after_index + 1;

    /* Shift items to make room */
    for (int i = q->count; i > insert_at; i--) {
        q->items[i] = q->items[i - 1];
    }
    q->items[insert_at] = *item;
    q->count++;

    rebuild_shuffle_order(q);
    return 0;
}

int aviation_queue_remove(AviationQueueManager *q, int index) {
    if (!q)
        return -1;
    if (index < 0 || index >= q->count)
        return -1;

    /* Shift items down */
    for (int i = index; i < q->count - 1; i++) {
        q->items[i] = q->items[i + 1];
    }
    q->count--;

    /* Adjust current index */
    if (index < q->current_index) {
        q->current_index--;
    } else if (index == q->current_index) {
        if (q->count == 0) {
            q->current_index = -1;
        } else if (q->current_index >= q->count) {
            q->current_index = q->count - 1;
        }
    }

    rebuild_shuffle_order(q);
    return 0;
}

int aviation_queue_move(AviationQueueManager *q, int from_index, int to_index) {
    if (!q)
        return -1;
    if (from_index < 0 || from_index >= q->count)
        return -1;
    if (to_index < 0 || to_index >= q->count)
        return -1;
    if (from_index == to_index)
        return 0;

    AviationMediaItem tmp = q->items[from_index];

    /* Remove from old position */
    if (from_index < to_index) {
        for (int i = from_index; i < to_index; i++) {
            q->items[i] = q->items[i + 1];
        }
    } else {
        for (int i = from_index; i > to_index; i--) {
            q->items[i] = q->items[i - 1];
        }
    }
    q->items[to_index] = tmp;

    /* Adjust current index */
    if (q->current_index == from_index) {
        q->current_index = to_index;
    } else if (from_index < q->current_index && to_index >= q->current_index) {
        q->current_index--;
    } else if (from_index > q->current_index && to_index <= q->current_index) {
        q->current_index++;
    }

    rebuild_shuffle_order(q);
    return 0;
}

void aviation_queue_clear(AviationQueueManager *q) {
    if (!q)
        return;
    q->count = 0;
    q->current_index = -1;
    q->shuffle_count = 0;
}

/* ─── Navigation ──────────────────────────────────────────────────── */

int aviation_queue_resolve_next(const AviationQueueManager *q) {
    if (!q || q->count == 0)
        return -1;

    if (q->current_index < 0) {
        return 0;
    }

    if (q->shuffle_enabled && q->shuffle_count > 0) {
        int shuffle_pos = find_shuffle_position(q, q->current_index);
        if (shuffle_pos < 0) {
            /* Current index not found in shuffle — return first shuffle item */
            return q->shuffle_count > 0 ? q->shuffle_order[0] : -1;
        }
        int next_pos = shuffle_pos + 1;
        if (next_pos < q->shuffle_count) {
            return q->shuffle_order[next_pos];
        }
        /* End of shuffle order */
        switch (q->repeat_mode) {
        case AVIATION_REPEAT_ALL:
            return q->shuffle_order[0];
        case AVIATION_REPEAT_ONE:
            return q->current_index;
        default:
            return -1;
        }
    }

    /* Non-shuffle mode */
    int next = q->current_index + 1;
    if (next < q->count) {
        return next;
    }
    switch (q->repeat_mode) {
    case AVIATION_REPEAT_ALL:
        return 0;
    case AVIATION_REPEAT_ONE:
        return q->current_index;
    default:
        return -1;
    }
}

int aviation_queue_resolve_next_n(const AviationQueueManager *q, int *out_indices, int max_count) {
    if (!q || !out_indices || max_count <= 0 || q->count == 0)
        return 0;

    int written = 0;

    if (q->repeat_mode == AVIATION_REPEAT_ONE) {
        /* Repeat-one: the same index repeats */
        int idx = q->current_index >= 0 ? q->current_index : 0;
        for (int i = 0; i < max_count; i++) {
            out_indices[i] = idx;
        }
        return max_count;
    }

    if (q->shuffle_enabled && q->shuffle_count > 0) {
        int shuffle_pos = find_shuffle_position(q, q->current_index);
        if (shuffle_pos < 0)
            shuffle_pos = -1; /* start from beginning */

        for (int i = 1; written < max_count; i++) {
            int next_pos = shuffle_pos + i;
            if (next_pos < q->shuffle_count) {
                out_indices[written++] = q->shuffle_order[next_pos];
            } else if (q->repeat_mode == AVIATION_REPEAT_ALL) {
                /* Wrap around */
                next_pos = next_pos % q->shuffle_count;
                out_indices[written++] = q->shuffle_order[next_pos];
            } else {
                break; /* No more items */
            }
        }
        return written;
    }

    /* Non-shuffle mode */
    for (int i = 1; written < max_count; i++) {
        int next = q->current_index + i;
        if (next < q->count) {
            out_indices[written++] = next;
        } else if (q->repeat_mode == AVIATION_REPEAT_ALL) {
            next = next % q->count;
            out_indices[written++] = next;
        } else {
            break;
        }
    }
    return written;
}

int aviation_queue_resolve_previous(const AviationQueueManager *q) {
    if (!q || q->count == 0)
        return -1;

    if (q->current_index < 0) {
        return -1;
    }

    if (q->shuffle_enabled && q->shuffle_count > 0) {
        int shuffle_pos = find_shuffle_position(q, q->current_index);
        if (shuffle_pos < 0) {
            /* Current index not found — return last shuffle item */
            return q->shuffle_count > 0 ? q->shuffle_order[q->shuffle_count - 1] : -1;
        }
        int prev_pos = shuffle_pos - 1;
        if (prev_pos >= 0) {
            return q->shuffle_order[prev_pos];
        }
        switch (q->repeat_mode) {
        case AVIATION_REPEAT_ALL:
            return q->shuffle_order[q->shuffle_count - 1];
        case AVIATION_REPEAT_ONE:
            return q->current_index;
        default:
            return -1;
        }
    }

    /* Non-shuffle mode */
    int prev = q->current_index - 1;
    if (prev >= 0) {
        return prev;
    }
    switch (q->repeat_mode) {
    case AVIATION_REPEAT_ALL:
        return q->count - 1;
    case AVIATION_REPEAT_ONE:
        return q->current_index;
    default:
        return -1;
    }
}

/* ─── State queries ───────────────────────────────────────────────── */

int aviation_queue_get_index(const AviationQueueManager *q) { return q ? q->current_index : -1; }

void aviation_queue_set_index(AviationQueueManager *q, int index) {
    if (q)
        q->current_index = index;
}

int aviation_queue_get_count(const AviationQueueManager *q) { return q ? q->count : 0; }

const AviationMediaItem *aviation_queue_get_item(const AviationQueueManager *q, int index) {
    if (!q || index < 0 || index >= q->count)
        return NULL;
    return &q->items[index];
}

const AviationMediaItem *aviation_queue_get_items(const AviationQueueManager *q) { return q ? q->items : NULL; }

bool aviation_queue_is_empty(const AviationQueueManager *q) { return !q || q->count == 0; }

/* ─── Shuffle ─────────────────────────────────────────────────────── */

void aviation_queue_set_shuffle(AviationQueueManager *q, bool enabled) {
    if (!q)
        return;
    q->shuffle_enabled = enabled;
    rebuild_shuffle_order(q);
}

bool aviation_queue_get_shuffle(const AviationQueueManager *q) { return q ? q->shuffle_enabled : false; }

/* ─── Repeat mode ─────────────────────────────────────────────────── */

void aviation_queue_set_repeat(AviationQueueManager *q, AviationRepeatMode mode) {
    if (q)
        q->repeat_mode = mode;
}

AviationRepeatMode aviation_queue_get_repeat(const AviationQueueManager *q) {
    return q ? q->repeat_mode : AVIATION_REPEAT_OFF;
}
