<template>
  <section class="full host-member-browser target-browser">
    <div class="member-browser-header">
      <div>
        <span class="eyebrow">{{ eyebrow }}</span>
        <h4>{{ title }}</h4>
        <p>{{ description }}</p>
      </div>
      <div class="member-selection-meter">
        <strong>{{ selectedIds.length }}</strong>
        <span>selected</span>
      </div>
    </div>

    <div :class="['member-toolbar', { 'target-browser-toolbar-compact': kind !== 'host' }]">
      <label class="member-search">
        <Search :size="15" />
        <input v-model="search" :placeholder="searchPlaceholder" />
        <button v-if="search" type="button" :aria-label="`Clear ${title} search`" @click="search = ''">
          <X :size="13" />
        </button>
      </label>
      <template v-if="kind === 'host'">
        <label>
          <span>OS</span>
          <select v-model="osFamily">
            <option value="">All OS types</option>
            <option value="windows">Windows</option>
            <option value="linux">Linux</option>
            <option value="other">Other</option>
          </select>
        </label>
        <label>
          <span>Source</span>
          <select v-model="source">
            <option value="">All sources</option>
            <option v-for="option in sourceOptions" :key="option" :value="option">{{ sourceLabel(option) }}</option>
          </select>
        </label>
        <label>
          <span>Transport</span>
          <select v-model="transport">
            <option value="">All transports</option>
            <option v-for="option in transportOptions" :key="option" :value="option">{{ option }}</option>
          </select>
        </label>
      </template>
      <button :class="['ghost-button compact', { active: selectedOnly }]" type="button" @click="selectedOnly = !selectedOnly">
        <ListChecks :size="15" />Selected
      </button>
    </div>

    <div class="member-results-bar">
      <span>{{ filteredItems.length }} matching {{ itemLabel }}</span>
      <div>
        <button class="ghost-button compact" type="button" :disabled="!pagedItems.length || pageAllSelected" @click="selectPage">Select page</button>
        <button class="ghost-button compact" type="button" :disabled="!pagedItems.some((item) => selectedIds.includes(item.id))" @click="clearPage">Clear page</button>
        <button class="ghost-button compact danger-text" type="button" :disabled="!selectedIds.length" @click="updateSelection([])">Clear all</button>
      </div>
    </div>

    <div class="member-table-wrap">
      <table class="member-table">
        <thead>
          <tr>
            <th class="select-col">
              <input
                type="checkbox"
                :checked="pageAllSelected"
                :disabled="!pagedItems.length"
                :aria-label="`Select all ${itemLabel} on this page`"
                @change="$event.target.checked ? selectPage() : clearPage()"
              />
            </th>
            <th v-for="column in columns" :key="column.key">
              <button v-if="column.sortable !== false" type="button" @click="toggleSort(column.key)">
                {{ column.label }} <component :is="sortIcon(column.key)" :size="13" />
              </button>
              <template v-else>{{ column.label }}</template>
            </th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="item in pagedItems" :key="item.id" :class="{ selected: selectedIds.includes(item.id) }">
            <td class="select-col">
              <input
                type="checkbox"
                :checked="selectedIds.includes(item.id)"
                :aria-label="`Select ${item.name}`"
                @change="toggleItem(item.id, $event.target.checked)"
              />
            </td>
            <td v-for="column in columns" :key="column.key">
              <template v-if="column.key === 'name'">
                <strong>{{ item.name }}</strong>
                <small>{{ secondaryText(item) }}</small>
              </template>
              <template v-else-if="column.key === 'address'"><code>{{ item.address || '-' }}</code></template>
              <template v-else-if="column.key === 'osFamily'"><span :class="['status-pill', item.osFamily || 'other']">{{ osFamilyLabel(item.osFamily) }}</span></template>
              <template v-else-if="column.key === 'transport'"><span class="status-pill neutral">{{ item.transport || '-' }}</span></template>
              <template v-else-if="column.key === 'sourceType'"><span :class="['status-pill', item.sourceType === 'vmware' ? 'dynamic' : 'manual']">{{ sourceLabel(item.sourceType) }}</span></template>
              <template v-else-if="column.key === 'mode'"><span :class="['status-pill', item.mode]">{{ item.mode || '-' }}</span></template>
              <template v-else-if="column.key === 'memberCount'">{{ item.memberCount || item.hostIds?.length || 0 }} host(s)</template>
              <template v-else-if="column.key === 'tags'"><span class="member-tags">{{ item.tags?.length ? item.tags.slice(0, 3).join(', ') : '-' }}</span></template>
              <template v-else-if="column.key === 'rules'"><span class="member-tags">{{ groupRuleSummary(item) }}</span></template>
              <template v-else>{{ item[column.key] || '-' }}</template>
            </td>
          </tr>
          <tr v-if="!pagedItems.length">
            <td :colspan="columns.length + 1" class="member-empty">No {{ itemLabel }} match the current filters.</td>
          </tr>
        </tbody>
      </table>
    </div>

    <div class="member-pagination">
      <label>
        <span>Rows</span>
        <select v-model.number="pageSize">
          <option :value="8">8</option>
          <option :value="12">12</option>
          <option :value="20">20</option>
        </select>
      </label>
      <span>Page {{ Math.min(page, pageCount) }} of {{ pageCount }}</span>
      <div>
        <button class="ghost-button compact" type="button" :disabled="page <= 1" @click="page -= 1">
          <ChevronLeft :size="15" />Previous
        </button>
        <button class="ghost-button compact" type="button" :disabled="page >= pageCount" @click="page += 1">
          Next<ChevronRight :size="15" />
        </button>
      </div>
    </div>
  </section>
</template>

<script setup>
import { computed, ref, watch } from 'vue';
import { ArrowDownAZ, ArrowUpAZ, ChevronsUpDown, ChevronLeft, ChevronRight, ListChecks, Search, X } from '@lucide/vue';

const props = defineProps({
  modelValue: { type: Array, default: () => [] },
  items: { type: Array, default: () => [] },
  kind: { type: String, default: 'host' },
  eyebrow: { type: String, default: 'TARGETS' },
  title: { type: String, required: true },
  description: { type: String, default: '' },
  searchPlaceholder: { type: String, default: 'Search targets...' }
});

const emit = defineEmits(['update:modelValue']);
const search = ref('');
const osFamily = ref('');
const source = ref('');
const transport = ref('');
const selectedOnly = ref(false);
const sort = ref('name');
const direction = ref('asc');
const page = ref(1);
const pageSize = ref(8);

const selectedIds = computed(() => props.modelValue || []);
const itemLabel = computed(() => props.kind === 'group' ? 'host group(s)' : 'host(s)');
const columns = computed(() => props.kind === 'group'
  ? [
      { key: 'name', label: 'Group' },
      { key: 'mode', label: 'Mode' },
      { key: 'memberCount', label: 'Members' },
      { key: 'rules', label: 'Rules', sortable: false }
    ]
  : [
      { key: 'name', label: 'Host' },
      { key: 'address', label: 'Address' },
      { key: 'osFamily', label: 'OS' },
      { key: 'transport', label: 'Transport' },
      { key: 'sourceType', label: 'Source' },
      { key: 'tags', label: 'Tags', sortable: false }
    ]);
const sourceOptions = computed(() => uniqueOptions(props.items.map((item) => item.sourceType || 'manual')));
const transportOptions = computed(() => uniqueOptions(props.items.map((item) => item.transport).filter(Boolean)));
const filteredItems = computed(() => {
  const term = search.value.trim().toLowerCase();
  const selected = new Set(selectedIds.value);
  return props.items.filter((item) => {
    if (selectedOnly.value && !selected.has(item.id)) return false;
    if (props.kind === 'host' && osFamily.value && (item.osFamily || 'other') !== osFamily.value) return false;
    if (props.kind === 'host' && source.value && (item.sourceType || 'manual') !== source.value) return false;
    if (props.kind === 'host' && transport.value && item.transport !== transport.value) return false;
    if (!term) return true;
    const values = props.kind === 'group'
      ? [item.name, item.mode, item.description, groupRuleSummary(item)]
      : [item.name, item.fqdn, item.address, item.osFamily, item.transport, item.sourceType, ...(item.tags || [])];
    return values.filter(Boolean).some((value) => String(value).toLowerCase().includes(term));
  }).sort((a, b) => {
    const result = sortableValue(a, sort.value).localeCompare(sortableValue(b, sort.value), undefined, { numeric: true, sensitivity: 'base' });
    return direction.value === 'asc' ? result : -result;
  });
});
const pageCount = computed(() => Math.max(1, Math.ceil(filteredItems.value.length / pageSize.value)));
const pagedItems = computed(() => filteredItems.value.slice((page.value - 1) * pageSize.value, (page.value - 1) * pageSize.value + pageSize.value));
const pageAllSelected = computed(() => Boolean(pagedItems.value.length) && pagedItems.value.every((item) => selectedIds.value.includes(item.id)));

watch([search, osFamily, source, transport, selectedOnly, pageSize], () => {
  page.value = 1;
});

watch(pageCount, (next) => {
  if (page.value > next) page.value = next;
});

function updateSelection(ids) {
  emit('update:modelValue', ids);
}

function toggleItem(id, checked) {
  const next = new Set(selectedIds.value);
  if (checked) next.add(id);
  else next.delete(id);
  updateSelection([...next]);
}

function selectPage() {
  updateSelection([...new Set([...selectedIds.value, ...pagedItems.value.map((item) => item.id)])]);
}

function clearPage() {
  const pageIds = new Set(pagedItems.value.map((item) => item.id));
  updateSelection(selectedIds.value.filter((id) => !pageIds.has(id)));
}

function toggleSort(key) {
  if (sort.value === key) {
    direction.value = direction.value === 'asc' ? 'desc' : 'asc';
    return;
  }
  sort.value = key;
  direction.value = 'asc';
}

function sortIcon(key) {
  if (sort.value !== key) return ChevronsUpDown;
  return direction.value === 'asc' ? ArrowUpAZ : ArrowDownAZ;
}

function uniqueOptions(values) {
  return [...new Set(values.filter(Boolean))].sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }));
}

function sortableValue(item, key) {
  if (key === 'osFamily') return item.osFamily || 'other';
  if (key === 'sourceType') return item.sourceType || 'manual';
  return String(item[key] || '');
}

function secondaryText(item) {
  return props.kind === 'group'
    ? `${item.mode || 'manual'} / ${item.memberCount || item.hostIds?.length || 0} host(s)`
    : item.fqdn || 'No FQDN recorded';
}

function sourceLabel(value = 'manual') {
  return value === 'vmware' ? 'VMware' : 'Manual';
}

function osFamilyLabel(value = 'other') {
  if (value === 'windows') return 'Windows';
  if (value === 'linux') return 'Linux';
  return 'Other';
}

function groupRuleSummary(item) {
  if (item.mode === 'manual') return 'Manual membership';
  return (item.rules || []).map((rule) => `${rule.field} ${rule.operator} ${rule.value}`).join(` ${item.matchMode || 'all'} `) || 'No rules';
}
</script>
