'use strict';
/**
 * Chat-style pagination for conversation messages.
 *
 * Ported from upstream claude-code-history-viewer
 * (src-tauri/src/commands/session/load.rs:1538 load_session_messages_paginated).
 * Contract:
 *   - Input `all` is chronologically sorted (earliest first).
 *   - offset=0 yields the most recent `limit` messages (end of the array).
 *   - Subsequent offsets walk backward in history.
 *   - Response.messages is still chronological so the UI can prepend
 *     earlier pages without resorting.
 *
 * See gap-reports/viewer-2026-04-23.md item D.
 */

const MIN_PAGE_SIZE = 1;
const MAX_PAGE_SIZE = 1000;

function _pageSize(limit) {
  const rawLimit = Number.isFinite(limit) ? Math.floor(limit) : 0;
  return Math.max(MIN_PAGE_SIZE, Math.min(MAX_PAGE_SIZE, rawLimit || MIN_PAGE_SIZE));
}

function _loadedOffset(offset) {
  return Math.max(0, Number.isFinite(offset) ? Math.floor(offset) : 0);
}

/**
 * @param {Array} all         — chronologically sorted messages
 * @param {number} offset     — how many most-recent messages are already loaded
 * @param {number} limit      — requested page size (clamped to [1, 1000])
 * @returns {{messages: Array, total: number, has_more: boolean, next_offset: number}}
 */
function paginateMessages(all, offset, limit) {
  const arr = Array.isArray(all) ? all : [];
  const total = arr.length;
  if (total === 0) {
    return { messages: [], total: 0, has_more: false, next_offset: 0 };
  }
  const alreadyLoaded = _loadedOffset(offset);
  const pageSize = _pageSize(limit);
  const remaining = Math.max(0, total - alreadyLoaded);
  const take = Math.min(pageSize, remaining);
  const endIdx = total - alreadyLoaded;        // exclusive
  const startIdx = Math.max(0, endIdx - take); // inclusive
  return {
    messages: arr.slice(startIdx, endIdx),
    total,
    has_more: startIdx > 0,
    next_offset: alreadyLoaded + take,
  };
}

function defaultIsTurnStart(message) {
  return !!message
    && String(message.role || '').trim() === 'user'
    && String(message.text || message.content || message.message || '').trim().length > 0;
}

function splitMessagesIntoTurns(all, options = {}) {
  const arr = Array.isArray(all) ? all : [];
  const isTurnStart = typeof options.isTurnStart === 'function'
    ? options.isTurnStart
    : defaultIsTurnStart;
  const setup = [];
  const turns = [];
  let current = null;

  arr.forEach((message, index) => {
    if (isTurnStart(message, index, arr)) {
      current = {
        type: 'turn',
        start_index: index,
        end_index: index,
        messages: [message],
      };
      turns.push(current);
      return;
    }
    if (current) {
      current.messages.push(message);
      current.end_index = index;
      return;
    }
    setup.push(message);
  });

  if (setup.length > 0) {
    turns.unshift({
      type: 'setup',
      start_index: 0,
      end_index: setup.length - 1,
      messages: setup,
    });
  }
  return turns;
}

/**
 * Paginates by complete semantic turns instead of raw rows.
 *
 * Review/conversation UIs group raw provider rows after fetching. Raw-message
 * pagination can begin in the middle of a long tool-heavy turn, which leaves
 * the renderer without the owning user prompt and makes it collapse everything
 * into a fake "setup" block. This helper keeps the same newest-first pagination
 * shape as paginateMessages, but `offset` and `limit` count complete turns.
 */
function paginateMessageTurns(all, offset, limit, options = {}) {
  const turns = splitMessagesIntoTurns(all, options);
  const total = turns.length;
  if (total === 0) {
    return {
      messages: [],
      total: 0,
      has_more: false,
      next_offset: 0,
      page_kind: 'turns',
      turn_count: 0,
    };
  }

  const alreadyLoaded = _loadedOffset(offset);
  const pageSize = _pageSize(limit);
  const remaining = Math.max(0, total - alreadyLoaded);
  const take = Math.min(pageSize, remaining);
  const endIdx = total - alreadyLoaded;
  const startIdx = Math.max(0, endIdx - take);
  const pageTurns = turns.slice(startIdx, endIdx);

  return {
    messages: pageTurns.flatMap(turn => turn.messages),
    total,
    has_more: startIdx > 0,
    next_offset: alreadyLoaded + take,
    page_kind: 'turns',
    turn_count: pageTurns.length,
    first_turn_index: pageTurns.length ? startIdx : -1,
    last_turn_index: pageTurns.length ? endIdx - 1 : -1,
  };
}

module.exports = {
  paginateMessages,
  paginateMessageTurns,
  splitMessagesIntoTurns,
  MIN_PAGE_SIZE,
  MAX_PAGE_SIZE,
};
