<template>
  <div class="container mx-auto p-4 max-w-2xl">
    <h1 class="text-2xl font-bold mb-6">Admin</h1>

    <div
      v-if="message.text"
      class="mb-4 rounded-lg px-4 py-2 transition-all duration-300"
      :class="message.type === 'error' ? 'bg-error/20 text-error' : 'bg-success/20 text-success'"
      role="alert"
    >
      {{ message.text }}
    </div>

    <div class="card bg-base-200 shadow-xl mb-6 transition-all duration-200">
      <div class="card-body">
        <h2 class="card-title gap-2">
          <icons-icon-users />
          Users
        </h2>
          <div class="flex flex-col gap-2">
            <div
              v-for="u in users"
              :key="u"
              class="flex items-center justify-between gap-3 w-full p-3 rounded-lg bg-base-300/50 hover:bg-base-300/70 transition-colors"
            >
              <div class="flex items-center gap-2 min-w-0">
                <div class="avatar avatar-placeholder">
                  <div class="bg-neutral text-neutral-content rounded-full w-8">
                    <span class="text-xs">{{ u[0]?.toUpperCase() }}</span>
                  </div>
                </div>
                <span class="font-medium">{{ u }}</span>
              </div>
              <NuxtLink :to="`/admin/users/${u}`" class="btn btn-outline btn-sm gap-1 shrink-0">
                <icons-icon-pencil /> Edit
              </NuxtLink>
            </div>
            <div v-if="!users.length" class="py-6 text-center text-base-content/60 rounded-lg bg-base-300/30">
              No users yet.
            </div>
            <NuxtLink to="/admin/users/new" class="btn btn-primary btn-sm mt-2 gap-1">
              <icons-icon-plus /> Add user
            </NuxtLink>
          </div>
        </div>
    </div>

    <div class="card bg-base-200 shadow-xl mb-6 transition-all duration-200">
      <div class="card-body">
        <h2 class="card-title gap-2">
          <icons-icon-map-pin />
          Maps
        </h2>
          <div class="overflow-x-auto">
            <table class="table table-sm table-zebra">
              <thead>
                <tr><th>ID</th><th>Name</th><th>Hidden</th><th>Priority</th><th class="text-right"></th></tr>
              </thead>
              <tbody>
                <tr v-for="map in maps" :key="map.ID" class="hover:bg-base-300">
                  <td>{{ map.ID }}</td>
                  <td>{{ map.Name }}</td>
                  <td>{{ map.Hidden ? 'Yes' : 'No' }}</td>
                  <td>{{ map.Priority ? 'Yes' : 'No' }}</td>
                  <td class="text-right">
                    <NuxtLink :to="`/admin/maps/${map.ID}`" class="btn btn-outline btn-sm gap-1">
                      <icons-icon-pencil /> Edit
                    </NuxtLink>
                  </td>
                </tr>
                <tr v-if="!maps.length">
                  <td colspan="5" class="text-base-content/60">No maps.</td>
                </tr>
              </tbody>
            </table>
          </div>
      </div>
    </div>

    <div class="card bg-base-200 shadow-xl mb-6 transition-all duration-200">
      <div class="card-body">
        <h2 class="card-title gap-2">
          <icons-icon-settings />
          Settings
        </h2>
          <div class="flex flex-col gap-4">
            <fieldset class="fieldset w-full max-w-xs">
              <label class="label" for="admin-settings-prefix">Prefix</label>
              <input
                id="admin-settings-prefix"
                v-model="settings.prefix"
                type="text"
                class="input input-sm w-full"
              />
            </fieldset>
            <fieldset class="fieldset w-full max-w-xs">
              <label class="label" for="admin-settings-title">Title</label>
              <input
                id="admin-settings-title"
                v-model="settings.title"
                type="text"
                class="input input-sm w-full"
              />
            </fieldset>
            <fieldset class="fieldset">
              <label class="label gap-2 cursor-pointer justify-start" for="admin-settings-default-hide">
                <input
                  id="admin-settings-default-hide"
                  v-model="settings.defaultHide"
                  type="checkbox"
                  class="checkbox checkbox-sm"
                />
                Default hide new maps
              </label>
            </fieldset>
          </div>
          <div class="flex justify-end mt-2">
            <button class="btn btn-primary btn-sm" :disabled="savingSettings" @click="saveSettings">
              <span v-if="savingSettings" class="loading loading-spinner loading-sm" />
              <span v-else>Save settings</span>
            </button>
          </div>
        </div>
    </div>

    <div class="card bg-base-200 shadow-xl mb-6 transition-all duration-200">
      <div class="card-body">
        <h2 class="card-title gap-2">
          <icons-icon-alert-triangle />
          Actions
        </h2>
          <div class="flex flex-col gap-3">
            <div>
              <a :href="api.adminExportUrl()" target="_blank" rel="noopener" class="btn btn-sm">
                Export zip
              </a>
            </div>
            <div>
              <button class="btn btn-sm" :disabled="rebuilding" @click="rebuildZooms">
                <span v-if="rebuilding" class="loading loading-spinner loading-sm" />
                <span v-else>Rebuild zooms</span>
              </button>
            </div>
            <div class="flex flex-col gap-2">
              <div class="flex flex-wrap items-center gap-2">
                <input ref="mergeFileRef" type="file" accept=".zip" class="hidden" @change="onMergeFile" />
                <button type="button" class="btn btn-sm" @click="mergeFileRef?.click()">
                  Choose merge file
                </button>
                <span class="text-sm text-base-content/70">
                  {{ mergeFile ? mergeFile.name : 'No file chosen' }}
                </span>
              </div>
              <form @submit.prevent="doMerge">
                <button type="submit" class="btn btn-sm btn-primary" :disabled="!mergeFile || merging">
                  <span v-if="merging" class="loading loading-spinner loading-sm" />
                  <span v-else>Merge</span>
                </button>
              </form>
            </div>
            <div class="border-t border-red-500/30 pt-4 mt-1 bg-error/5 rounded-lg p-3 -mx-1">
              <p class="text-sm font-medium text-error/90 mb-2">Danger zone</p>
              <button class="btn btn-sm btn-error" :disabled="wiping" @click="confirmWipe">
                <span v-if="wiping" class="loading loading-spinner loading-sm" />
                <span v-else>Wipe all data</span>
              </button>
            </div>
          </div>
      </div>
    </div>

    <dialog ref="wipeModalRef" class="modal" aria-labelledby="wipe-modal-title">
      <div class="modal-box">
        <h2 id="wipe-modal-title" class="font-bold text-lg mb-2">Confirm wipe</h2>
        <p>Wipe all grids, markers, tiles and maps? This cannot be undone.</p>
        <div class="modal-action">
          <form method="dialog">
            <button class="btn">Cancel</button>
          </form>
          <button class="btn btn-error" :disabled="wiping" @click="doWipe">Wipe</button>
        </div>
      </div>
      <form method="dialog" class="modal-backdrop"><button aria-label="Close">Close</button></form>
    </dialog>
  </div>
</template>

<script setup lang="ts">
definePageMeta({ middleware: 'admin' })

const api = useMapApi()
const users = ref<string[]>([])
const maps = ref<Array<{ ID: number; Name: string; Hidden: boolean; Priority: boolean }>>([])
const settings = ref({ prefix: '', defaultHide: false, title: '' })
const savingSettings = ref(false)
const rebuilding = ref(false)
const wiping = ref(false)
const merging = ref(false)
const mergeFile = ref<File | null>(null)
const mergeFileRef = ref<HTMLInputElement | null>(null)
const wipeModalRef = ref<HTMLDialogElement | null>(null)

const message = ref<{ type: 'success' | 'error'; text: string }>({ type: 'success', text: '' })
let messageTimeout: ReturnType<typeof setTimeout> | null = null
function setMessage(type: 'success' | 'error', text: string) {
  message.value = { type, text }
  if (messageTimeout) clearTimeout(messageTimeout)
  messageTimeout = setTimeout(() => {
    message.value = { type: 'success', text: '' }
    messageTimeout = null
  }, 4000)
}

onMounted(async () => {
  await Promise.all([loadUsers(), loadMaps(), loadSettings()])
})

async function loadUsers() {
  try {
    users.value = await api.adminUsers()
  } catch {
    users.value = []
  }
}

async function loadMaps() {
  try {
    maps.value = await api.adminMaps()
  } catch {
    maps.value = []
  }
}

async function loadSettings() {
  try {
    const s = await api.adminSettings()
    settings.value = { prefix: s.prefix ?? '', defaultHide: s.defaultHide ?? false, title: s.title ?? '' }
  } catch {
    //
  }
}

async function saveSettings() {
  savingSettings.value = true
  try {
    await api.adminSettingsPost(settings.value)
    setMessage('success', 'Settings saved.')
  } catch (e) {
    setMessage('error', (e as Error)?.message ?? 'Failed to save settings.')
  } finally {
    savingSettings.value = false
  }
}

async function rebuildZooms() {
  rebuilding.value = true
  try {
    await api.adminRebuildZooms()
    setMessage('success', 'Zooms rebuilt.')
  } catch (e) {
    setMessage('error', (e as Error)?.message ?? 'Failed to rebuild zooms.')
  } finally {
    rebuilding.value = false
  }
}

function confirmWipe() {
  wipeModalRef.value?.showModal()
}

async function doWipe() {
  wiping.value = true
  try {
    await api.adminWipe()
    wipeModalRef.value?.close()
    await loadMaps()
    setMessage('success', 'All data wiped.')
  } catch (e) {
    setMessage('error', (e as Error)?.message ?? 'Failed to wipe.')
  } finally {
    wiping.value = false
  }
}

function onMergeFile(e: Event) {
  const input = e.target as HTMLInputElement
  mergeFile.value = input.files?.[0] ?? null
}

async function doMerge() {
  if (!mergeFile.value) return
  merging.value = true
  try {
    const fd = new FormData()
    fd.append('merge', mergeFile.value)
    await api.adminMerge(fd)
    mergeFile.value = null
    if (mergeFileRef.value) mergeFileRef.value.value = ''
    await loadMaps()
    setMessage('success', 'Merge completed.')
  } catch (e) {
    setMessage('error', (e as Error)?.message ?? 'Merge failed.')
  } finally {
    merging.value = false
  }
}
</script>
