<template>
	<div class="search-bar" :class="{ 'search-bar--open': showResults }">
		<div class="search-bar__input-wrapper">
			<Magnify :size="18" class="search-bar__icon" />
			<input ref="inputRef"
				v-model="query"
				type="text"
				class="search-bar__input"
				placeholder="Mitglieder suchen..."
				autocomplete="off"
				@input="onInput"
				@focus="onFocus"
				@blur="onBlur"
				@keydown.down.prevent="moveSelection(1)"
				@keydown.up.prevent="moveSelection(-1)"
				@keydown.enter.prevent="selectCurrent"
				@keydown.escape="close">
			<button v-if="query"
				class="search-bar__clear"
				title="Leeren"
				@mousedown.prevent="clearQuery">
				&#10005;
			</button>
		</div>

		<!-- Results dropdown -->
		<div v-if="showResults" class="search-bar__dropdown">
			<!-- Loading -->
			<div v-if="loading" class="search-bar__loading">
				Suche...
			</div>

			<!-- Error (shown instead of "no results" when the request failed) -->
			<div v-else-if="error" class="search-bar__error">
				<strong>Suche fehlgeschlagen</strong>
				<div class="search-bar__error-msg">{{ error }}</div>
				<button class="search-bar__retry" @mousedown.prevent="performSearch">
					Erneut versuchen
				</button>
			</div>

			<!-- No results -->
			<div v-else-if="results.length === 0 && query.trim().length >= 2" class="search-bar__empty">
				Keine Ergebnisse für "{{ query }}"
			</div>

			<!-- Min chars hint -->
			<div v-else-if="query.trim().length < 2" class="search-bar__hint">
				Mindestens 2 Zeichen eingeben
			</div>

			<!-- Results list -->
			<ul v-else class="search-bar__results">
				<li v-for="(result, index) in results"
					:key="result.id"
					:class="{ 'search-bar__result--selected': index === selectedIndex }"
					class="search-bar__result"
					@mousedown.prevent="navigateToMember(result.id)"
					@mouseenter="selectedIndex = index">
					<div class="search-bar__result-name">
						{{ result.nachname }}, {{ result.vorname }}
					</div>
					<div v-if="result.matchContext" class="search-bar__result-context">
						{{ result.matchContext }}
					</div>
					<div class="search-bar__result-meta">
						<span :class="'search-bar__status search-bar__status--' + result.status">
							{{ formatStatus(result.status) }}
						</span>
						<span v-if="result.rolle === 'erziehungsberechtigter'" class="search-bar__rolle">
							Erziehungsberechtigt
						</span>
					</div>
				</li>
			</ul>
		</div>
	</div>
</template>

<script setup>
import { ref, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
import Magnify from 'vue-material-design-icons/Magnify.vue'

const router = useRouter()

const query = ref('')
const results = ref([])
const loading = ref(false)
const error = ref(null)
const showResults = ref(false)
const selectedIndex = ref(-1)
const inputRef = ref(null)

let searchTimeout = null
let inflightRequestId = 0

// ── Search logic ────────────────────────────────────────────────────

function onInput() {
	selectedIndex.value = -1
	error.value = null
	clearTimeout(searchTimeout)

	if (query.value.trim().length < 2) {
		results.value = []
		return
	}

	searchTimeout = setTimeout(() => {
		performSearch()
	}, 300)
}

async function performSearch() {
	if (query.value.trim().length < 2) return

	const requestId = ++inflightRequestId
	loading.value = true
	error.value = null

	try {
		const url = generateUrl('/apps/mitgliederverwaltung/api/v1/members/search')
		const response = await axios.get(url, {
			params: { q: query.value.trim(), limit: 10 },
			timeout: 10000,
		})
		// Drop stale responses — only the most recent request wins
		if (requestId !== inflightRequestId) return
		results.value = response.data.data || []
	} catch (err) {
		if (requestId !== inflightRequestId) return
		console.error('Search failed:', err)
		results.value = []
		error.value = formatSearchError(err)
	} finally {
		if (requestId === inflightRequestId) {
			loading.value = false
		}
	}
}

function formatSearchError(err) {
	if (err?.code === 'ECONNABORTED' || /timeout/i.test(err?.message || '')) {
		return 'Zeitüberschreitung der Anfrage (10 s). Server ist überlastet oder die Verbindung ist langsam.'
	}
	const status = err?.response?.status
	if (status === 401 || status === 403) {
		return 'Sitzung abgelaufen. Bitte die Seite neu laden und erneut anmelden.'
	}
	if (status === 429) {
		return 'Zu viele Anfragen. Nextcloud hat die Suche vorübergehend gesperrt — kurz warten und erneut versuchen.'
	}
	if (status >= 500 && status < 600) {
		const serverMsg = err.response?.data?.error || 'Serverfehler'
		return `HTTP ${status}: ${serverMsg}`
	}
	if (status) {
		return `HTTP ${status}: ${err.response?.data?.error || err.message}`
	}
	if (err?.message) {
		return `Netzwerkfehler: ${err.message}`
	}
	return 'Unbekannter Fehler.'
}

// ── Dropdown visibility ─────────────────────────────────────────────

function onFocus() {
	showResults.value = true
	if (query.value.trim().length >= 2 && results.value.length === 0) {
		performSearch()
	}
}

function onBlur() {
	// Delay to allow click events on results
	setTimeout(() => {
		showResults.value = false
	}, 200)
}

function close() {
	showResults.value = false
	inputRef.value?.blur()
}

function clearQuery() {
	query.value = ''
	results.value = []
	selectedIndex.value = -1
	error.value = null
	nextTick(() => {
		inputRef.value?.focus()
	})
}

// ── Keyboard navigation ─────────────────────────────────────────────

function moveSelection(direction) {
	if (results.value.length === 0) return

	selectedIndex.value += direction

	if (selectedIndex.value < 0) {
		selectedIndex.value = results.value.length - 1
	} else if (selectedIndex.value >= results.value.length) {
		selectedIndex.value = 0
	}
}

function selectCurrent() {
	if (selectedIndex.value >= 0 && selectedIndex.value < results.value.length) {
		navigateToMember(results.value[selectedIndex.value].id)
	}
}

// ── Navigation ──────────────────────────────────────────────────────

function navigateToMember(memberId) {
	showResults.value = false
	query.value = ''
	results.value = []
	selectedIndex.value = -1
	router.push({ name: 'member-detail', params: { id: memberId } })
}

// ── Formatting ──────────────────────────────────────────────────────

function formatStatus(status) {
	const map = {
		aktiv: 'Aktiv',
		inaktiv: 'Inaktiv',
		geloescht: 'Gelöscht',
	}
	return map[status] || status
}
</script>

<style scoped>
.search-bar {
	position: relative;
	width: 280px;
}

.search-bar__input-wrapper {
	display: flex;
	align-items: center;
	border: 1px solid var(--color-border);
	border-radius: var(--border-radius-pill);
	background: var(--color-main-background);
	padding: 0 8px;
	transition: border-color 0.15s ease;
}

.search-bar--open .search-bar__input-wrapper {
	border-color: var(--color-primary);
}

.search-bar__icon {
	color: var(--color-text-lighter);
	flex-shrink: 0;
}

.search-bar__input {
	flex: 1;
	border: none;
	background: none;
	padding: 6px 8px;
	color: var(--color-text);
	outline: none;
	font-size: 0.9em;
}

.search-bar__input::placeholder {
	color: var(--color-text-lighter);
}

.search-bar__clear {
	background: none;
	border: none;
	color: var(--color-text-lighter);
	cursor: pointer;
	padding: 2px 4px;
	font-size: 0.8em;
}

.search-bar__clear:hover {
	color: var(--color-error);
}

/* Dropdown */
.search-bar__dropdown {
	position: absolute;
	top: 100%;
	left: 0;
	right: 0;
	margin-top: 4px;
	background: var(--color-main-background);
	border: 1px solid var(--color-border);
	border-radius: var(--border-radius);
	box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
	max-height: 400px;
	overflow-y: auto;
	z-index: 1000;
}

.search-bar__loading,
.search-bar__empty,
.search-bar__hint {
	padding: 12px 16px;
	color: var(--color-text-lighter);
	font-size: 0.9em;
	text-align: center;
}

.search-bar__error {
	padding: 12px 16px;
	color: var(--color-error);
	background: color-mix(in srgb, var(--color-error) 10%, transparent);
	font-size: 0.85em;
	border-radius: var(--border-radius);
	margin: 4px;
}

.search-bar__error strong {
	display: block;
	margin-bottom: 4px;
}

.search-bar__error-msg {
	color: var(--color-text);
	margin-bottom: 8px;
	word-break: break-word;
}

.search-bar__retry {
	background: var(--color-error);
	color: white;
	border: none;
	border-radius: var(--border-radius);
	padding: 4px 10px;
	cursor: pointer;
	font-size: 0.85em;
}

.search-bar__results {
	list-style: none;
	margin: 0;
	padding: 4px 0;
}

.search-bar__result {
	padding: 8px 16px;
	cursor: pointer;
	transition: background-color 0.1s ease;
}

.search-bar__result:hover,
.search-bar__result--selected {
	background: var(--color-background-hover);
}

.search-bar__result-name {
	font-weight: 500;
	font-size: 0.95em;
}

.search-bar__result-context {
	color: var(--color-text-lighter);
	font-size: 0.8em;
	margin-top: 2px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.search-bar__result-meta {
	display: flex;
	gap: 8px;
	margin-top: 2px;
}

.search-bar__status {
	display: inline-block;
	padding: 1px 6px;
	border-radius: var(--border-radius-pill);
	font-size: 0.75em;
	font-weight: 500;
}

.search-bar__status--aktiv {
	background: var(--color-success);
	color: white;
}

.search-bar__status--inaktiv {
	background: var(--color-warning);
	color: white;
}

.search-bar__status--geloescht {
	background: var(--color-error);
	color: white;
}

.search-bar__rolle {
	font-size: 0.75em;
	color: var(--color-text-lighter);
}
</style>
