import { computed, reactive, ref, watch } from 'vue';

function rowsFrom(source) {
  const value = typeof source === 'function' ? source() : source?.value ?? source;
  return Array.isArray(value) ? value : [];
}

export function useLedger(source, options = {}) {
  const query = ref('');
  const filters = reactive(Object.fromEntries(Object.keys(options.filters || {}).map(key => [key, ''])));
  const page = ref(1);
  const pageSize = ref(options.pageSize || 20);
  const sourceRows = computed(() => rowsFrom(source));
  const filtered = computed(() => {
    const needle = query.value.trim().toLocaleLowerCase('zh-CN');
    return sourceRows.value.filter(row => {
      if (needle) {
        const haystack = options.searchText ? options.searchText(row) : JSON.stringify(row);
        if (!String(haystack || '').toLocaleLowerCase('zh-CN').includes(needle)) return false;
      }
      return Object.entries(options.filters || {}).every(([key, predicate]) => {
        const value = filters[key];
        return !value || predicate(row, value);
      });
    });
  });
  const total = computed(() => filtered.value.length);
  const totalPages = computed(() => Math.max(1, Math.ceil(total.value / pageSize.value)));
  const rows = computed(() => {
    const start = (page.value - 1) * pageSize.value;
    return filtered.value.slice(start, start + pageSize.value);
  });
  const pageRows = computed(() => rows.value);
  const rangeStart = computed(() => total.value ? (page.value - 1) * pageSize.value + 1 : 0);
  const rangeEnd = computed(() => Math.min(total.value, page.value * pageSize.value));

  watch([query, pageSize, ...Object.keys(filters).map(key => () => filters[key])], () => { page.value = 1; });
  watch(totalPages, count => { if (page.value > count) page.value = count; });

  function clear() {
    query.value = '';
    for (const key of Object.keys(filters)) filters[key] = '';
    page.value = 1;
  }

  return reactive({ query, filters, page, pageSize, sourceRows, filtered, total, totalPages, rows, pageRows, rangeStart, rangeEnd, clear });
}
