<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { usePluginStore } from '@/stores/plugins'
import type { UmodPlugin } from '@/stores/plugins'
import { useToastStore } from '@/stores/toast'
import type { PluginEntry } from '@/types'
import Panel from '@/components/ds/data/Panel.vue'
import Button from '@/components/ds/core/Button.vue'
import Badge from '@/components/ds/core/Badge.vue'
import Icon from '@/components/ds/core/Icon.vue'
import IconButton from '@/components/ds/core/IconButton.vue'
import Input from '@/components/ds/forms/Input.vue'
import EmptyState from '@/components/ds/feedback/EmptyState.vue'
import Alert from '@/components/ds/feedback/Alert.vue'
import Tabs from '@/components/ds/navigation/Tabs.vue'

const pluginStore = usePluginStore()
const toast = useToastStore()

const searchQuery = ref('')
const tab = ref<'installed' | 'browse' | 'upload'>('installed')
const browseQuery = ref('')
const browsePage = ref(1)
const browseDebounce = ref<ReturnType<typeof setTimeout> | null>(null)
const installing = ref<string | null>(null)

// Upload state
const uploadFile = ref<File | null>(null)
const isDragOver = ref(false)
const isUploading = ref(false)
const uploadInput = ref<HTMLInputElement | null>(null)

const filteredPlugins = computed(() => {
  let result = pluginStore.plugins
  if (searchQuery.value.trim()) {
    const q = searchQuery.value.toLowerCase()
    result = result.filter((p: PluginEntry) => p.plugin_name.toLowerCase().includes(q))
  }
  return result
})

const browsePlugins = computed(() => pluginStore.browseResults?.data ?? [])

const loadedCount = computed(() => pluginStore.plugins.filter((p: PluginEntry) => p.is_loaded).length)

const tabItems = [
  { value: 'installed', label: 'Installed' },
  { value: 'browse', label: 'Browse uMod' },
  { value: 'upload', label: 'Upload custom' },
]

function sourceLabel(source: string): string {
  switch (source) {
    case 'umod': return 'uMod'
    case 'corrosion_module': return 'Corrosion'
    case 'manual': return 'Manual'
    default: return source
  }
}

function sourceTone(source: string): 'online' | 'accent' | 'neutral' {
  switch (source) {
    case 'umod': return 'online'
    case 'corrosion_module': return 'accent'
    default: return 'neutral'
  }
}

async function handleToggleLoad(plugin: PluginEntry) {
  try {
    await pluginStore.reloadPlugin(plugin.id)
    toast.success(`${plugin.plugin_name} ${plugin.is_loaded ? 'unloaded' : 'loaded'} successfully`)
    await pluginStore.fetchPlugins()
  } catch {
    toast.error(`Failed to toggle ${plugin.plugin_name}`)
  }
}

async function handleUninstall(plugin: PluginEntry) {
  if (!confirm(`Uninstall ${plugin.plugin_name}? This cannot be undone.`)) return
  try {
    await pluginStore.uninstallPlugin(plugin.id)
    toast.success(`${plugin.plugin_name} uninstalled`)
  } catch {
    toast.error(`Failed to uninstall ${plugin.plugin_name}`)
  }
}

async function handleBrowseSearch(page = 1) {
  if (!browseQuery.value.trim()) return
  browsePage.value = page
  try {
    await pluginStore.browseUmod(browseQuery.value.trim(), page)
  } catch {
    toast.error('Failed to search uMod plugins')
  }
}

function scheduleBrowseSearch() {
  if (browseDebounce.value) clearTimeout(browseDebounce.value)
  browseDebounce.value = setTimeout(() => handleBrowseSearch(1), 400)
}

function browsePrev() {
  if (browsePage.value > 1) handleBrowseSearch(browsePage.value - 1)
}

function browseNext() {
  if (pluginStore.browseResults && browsePage.value < pluginStore.browseResults.last_page) {
    handleBrowseSearch(browsePage.value + 1)
  }
}

async function installFromBrowse(result: UmodPlugin) {
  installing.value = result.name
  try {
    await pluginStore.installPlugin({ plugin_name: result.name, umod_slug: result.slug, source: 'umod' })
    toast.success(`${result.name} installed`)
  } catch {
    toast.error(`Failed to install ${result.name}`)
  } finally {
    installing.value = null
  }
}

// Upload helpers
function isAlreadyInstalled(name: string): boolean {
  return pluginStore.plugins.some((p: PluginEntry) => p.plugin_name === name)
}

function validateCsFile(file: File): string | null {
  if (!file.name.toLowerCase().endsWith('.cs')) {
    return 'Only .cs plugin files are accepted'
  }
  if (file.size > 5 * 1024 * 1024) {
    return 'File must be under 5 MB'
  }
  return null
}

function handleFilePick(event: Event) {
  const input = event.target as HTMLInputElement
  const file = input.files?.[0]
  if (!file) return
  const err = validateCsFile(file)
  if (err) { toast.error(err); return }
  uploadFile.value = file
}

function handleDrop(event: DragEvent) {
  isDragOver.value = false
  const file = event.dataTransfer?.files[0]
  if (!file) return
  const err = validateCsFile(file)
  if (err) { toast.error(err); return }
  uploadFile.value = file
}

function clearUpload() {
  uploadFile.value = null
  if (uploadInput.value) uploadInput.value.value = ''
}

async function handleUpload() {
  if (!uploadFile.value) return
  isUploading.value = true
  try {
    await pluginStore.uploadPlugin(uploadFile.value)
    toast.success(`${uploadFile.value.name} uploaded successfully`)
    clearUpload()
    tab.value = 'installed'
  } catch (err) {
    toast.error((err as Error).message || 'Upload failed')
  } finally {
    isUploading.value = false
  }
}

onMounted(() => {
  pluginStore.fetchPlugins()
})
</script>

<template>
  <div class="plv">
    <!-- Page head -->
    <div class="plv__head">
      <div class="plv__head-id">
        <div class="plv__head-chip">
          <Icon name="puzzle" :size="20" :stroke-width="2" />
        </div>
        <div>
          <div class="t-eyebrow">Plugin management</div>
          <h1 class="plv__title">Plugins</h1>
        </div>
      </div>
      <div class="plv__head-actions">
        <div class="plv__stat-pill">
          <span class="plv__stat-num">{{ loadedCount }}</span>
          <span class="plv__stat-sep">/</span>
          <span class="plv__stat-total">{{ pluginStore.plugins.length }}</span>
          <span class="plv__stat-label">loaded</span>
        </div>
        <Button
          variant="secondary"
          size="sm"
          icon="refresh-cw"
          :loading="pluginStore.isLoading"
          :disabled="pluginStore.isLoading"
          @click="pluginStore.fetchPlugins()"
        >Refresh</Button>
      </div>
    </div>

    <!-- Tab bar + search -->
    <div class="plv__toolbar">
      <Tabs v-model="tab" :items="tabItems" />
      <Input
        v-if="tab === 'installed'"
        v-model="searchQuery"
        icon="search"
        placeholder="Search installed plugins…"
        size="sm"
        style="max-width: 280px;"
      />
      <Input
        v-if="tab === 'browse'"
        v-model="browseQuery"
        icon="search"
        placeholder="Search uMod plugins…"
        size="sm"
        style="max-width: 280px;"
        @input="scheduleBrowseSearch"
        @keydown.enter="handleBrowseSearch(1)"
      />
    </div>

    <!-- ===== INSTALLED TAB ===== -->
    <Panel v-if="tab === 'installed'" :flush-body="true">
      <EmptyState
        v-if="filteredPlugins.length === 0 && !pluginStore.isLoading"
        icon="puzzle"
        title="No plugins installed"
        :description="searchQuery ? `No plugins matching &quot;${searchQuery}&quot;.` : 'Install plugins from the Browse uMod tab or upload a custom .cs file.'"
      />
      <div v-else-if="pluginStore.isLoading && filteredPlugins.length === 0" class="plv__loading">
        <Icon name="loader" :size="20" class="plv__spin" />
        <span>Loading plugins…</span>
      </div>
      <table v-else class="plv__table">
        <thead>
          <tr>
            <th>Plugin</th>
            <th>Version</th>
            <th>Source</th>
            <th>Status</th>
            <th>Wipe behavior</th>
            <th class="plv__th-right">Actions</th>
          </tr>
        </thead>
        <tbody>
          <tr
            v-for="plugin in filteredPlugins"
            :key="plugin.id"
          >
            <td class="plv__plugin-name">{{ plugin.plugin_name }}</td>
            <td class="plv__mono">{{ plugin.plugin_version ?? '—' }}</td>
            <td>
              <Badge :tone="sourceTone(plugin.source)" size="md">{{ sourceLabel(plugin.source) }}</Badge>
            </td>
            <td>
              <Badge
                :tone="plugin.is_loaded ? 'online' : 'offline'"
                :dot="true"
                :pulse="plugin.is_loaded"
              >{{ plugin.is_loaded ? 'Loaded' : 'Unloaded' }}</Badge>
            </td>
            <td class="plv__secondary plv__wipe-cell">
              <template v-if="plugin.never_wipe">Never wipe</template>
              <template v-else>
                {{ [plugin.wipe_on_map && 'Map', plugin.wipe_on_bp && 'BP', plugin.wipe_on_full && 'Full'].filter(Boolean).join(', ') || 'None' }}
              </template>
            </td>
            <td class="plv__td-right">
              <div class="plv__row-actions">
                <IconButton
                  :icon="plugin.is_loaded ? 'power' : 'play'"
                  variant="ghost"
                  size="sm"
                  :label="plugin.is_loaded ? 'Unload' : 'Load'"
                  @click="handleToggleLoad(plugin)"
                />
                <IconButton
                  icon="trash-2"
                  variant="danger"
                  size="sm"
                  label="Uninstall"
                  @click="handleUninstall(plugin)"
                />
              </div>
            </td>
          </tr>
        </tbody>
      </table>
    </Panel>

    <!-- ===== BROWSE UMOD TAB ===== -->
    <div v-if="tab === 'browse'">
      <!-- No search yet -->
      <Panel v-if="!browseQuery.trim() && browsePlugins.length === 0">
        <EmptyState
          icon="search"
          title="Search uMod"
          description="Type a plugin name above to search the uMod plugin directory."
        />
      </Panel>

      <!-- Loading -->
      <Panel v-else-if="pluginStore.isBrowseLoading">
        <div class="plv__loading">
          <Icon name="loader" :size="20" class="plv__spin" />
          <span>Searching uMod…</span>
        </div>
      </Panel>

      <!-- No results -->
      <Panel v-else-if="browseQuery.trim() && browsePlugins.length === 0">
        <EmptyState
          icon="download"
          title="No plugins found"
          :description="`No uMod plugins matched &quot;${browseQuery}&quot;. Try a different search term.`"
        />
      </Panel>

      <!-- Results -->
      <Panel v-else :flush-body="true">
        <template #actions>
          <span v-if="pluginStore.browseResults" class="plv__browse-meta">
            {{ pluginStore.browseResults.total.toLocaleString() }} plugins
            &middot; page {{ pluginStore.browseResults.current_page }}/{{ pluginStore.browseResults.last_page }}
          </span>
          <Button
            variant="ghost"
            size="sm"
            icon="chevron-left"
            :disabled="browsePage <= 1 || pluginStore.isBrowseLoading"
            @click="browsePrev"
          >Prev</Button>
          <Button
            variant="ghost"
            size="sm"
            icon-right="chevron-right"
            :disabled="!pluginStore.browseResults || browsePage >= pluginStore.browseResults.last_page || pluginStore.isBrowseLoading"
            @click="browseNext"
          >Next</Button>
        </template>
        <table class="plv__table">
          <thead>
            <tr>
              <th>Plugin</th>
              <th>Author</th>
              <th>Version</th>
              <th>Downloads</th>
              <th class="plv__th-right">Action</th>
            </tr>
          </thead>
          <tbody>
            <tr
              v-for="result in browsePlugins"
              :key="result.name"
            >
              <td>
                <div class="plv__browse-name">{{ result.title }}</div>
                <div v-if="result.description" class="plv__browse-desc">{{ result.description }}</div>
              </td>
              <td class="plv__secondary">{{ result.author ?? '—' }}</td>
              <td class="plv__mono">{{ result.latest_release_version_formatted ?? '—' }}</td>
              <td class="plv__secondary plv__mono">{{ result.downloads_shortened ?? '—' }}</td>
              <td class="plv__td-right">
                <Button
                  size="sm"
                  :variant="isAlreadyInstalled(result.name) ? 'secondary' : 'primary'"
                  :icon="installing === result.name ? 'loader' : 'download'"
                  :loading="installing === result.name"
                  :disabled="installing === result.name || isAlreadyInstalled(result.name)"
                  @click="installFromBrowse(result)"
                >{{ isAlreadyInstalled(result.name) ? 'Installed' : 'Install' }}</Button>
              </td>
            </tr>
          </tbody>
        </table>
        <!-- Bottom pagination -->
        <div v-if="pluginStore.browseResults && pluginStore.browseResults.last_page > 1" class="plv__browse-foot">
          <span class="plv__browse-meta">
            Page {{ pluginStore.browseResults.current_page }} of {{ pluginStore.browseResults.last_page }}
          </span>
          <div class="plv__browse-pag">
            <Button
              variant="secondary"
              size="sm"
              icon="chevron-left"
              :disabled="browsePage <= 1 || pluginStore.isBrowseLoading"
              @click="browsePrev"
            >Previous</Button>
            <Button
              variant="secondary"
              size="sm"
              icon-right="chevron-right"
              :disabled="!pluginStore.browseResults || browsePage >= pluginStore.browseResults.last_page || pluginStore.isBrowseLoading"
              @click="browseNext"
            >Next</Button>
          </div>
        </div>
      </Panel>
    </div>

    <!-- ===== UPLOAD CUSTOM TAB ===== -->
    <div v-if="tab === 'upload'" class="plv__upload-wrap">
      <Panel title="Upload custom plugin" subtitle="Upload .cs plugin files from Lone Wolf, Codefling, or your own code. Max 5 MB.">

        <!-- Drop zone -->
        <div
          class="plv__dropzone"
          :class="{
            'plv__dropzone--active': isDragOver,
            'plv__dropzone--ready': !!uploadFile && !isDragOver,
          }"
          @dragover.prevent="isDragOver = true"
          @dragleave.prevent="isDragOver = false"
          @drop.prevent="handleDrop"
          @click="uploadInput?.click()"
        >
          <input
            ref="uploadInput"
            type="file"
            accept=".cs"
            class="plv__file-hidden"
            @change="handleFilePick"
          />

          <!-- No file -->
          <template v-if="!uploadFile">
            <div class="plv__drop-icon">
              <Icon name="upload" :size="22" :stroke-width="1.75" />
            </div>
            <p class="plv__drop-label">Drop your .cs file here</p>
            <p class="plv__drop-hint">or click to browse</p>
          </template>

          <!-- File selected -->
          <template v-else>
            <div class="plv__file-row">
              <div class="plv__file-icon">
                <Icon name="puzzle" :size="20" :stroke-width="1.75" />
              </div>
              <div class="plv__file-info">
                <div class="plv__file-name">{{ uploadFile.name }}</div>
                <div class="plv__file-size">{{ (uploadFile.size / 1024).toFixed(1) }} KB</div>
              </div>
              <IconButton
                icon="x"
                variant="ghost"
                size="sm"
                label="Remove"
                @click.stop="clearUpload"
              />
            </div>
          </template>
        </div>

        <!-- Actions -->
        <div class="plv__upload-actions">
          <Button
            icon="upload"
            :loading="isUploading"
            :disabled="!uploadFile || isUploading"
            @click="handleUpload"
          >{{ isUploading ? 'Uploading…' : 'Upload plugin' }}</Button>
          <Button
            v-if="uploadFile"
            variant="ghost"
            @click="clearUpload"
          >Cancel</Button>
        </div>
      </Panel>

      <Alert tone="info">
        The plugin will be registered in your plugin list immediately. Your host agent must be connected
        for the file to be delivered to the game server. If the agent is offline, re-upload once it reconnects.
      </Alert>
    </div>
  </div>
</template>

<style scoped>
.plv { max-width: 1200px; margin: 0 auto; display: flex; flex-direction: column; gap: 16px; }

/* Page head */
.plv__head {
  display: flex; align-items: flex-end; justify-content: space-between;
  flex-wrap: wrap; gap: 12px;
}
.plv__head-id { display: flex; align-items: center; gap: 12px; }
.plv__head-chip {
  width: 40px; height: 40px; flex: none; border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center;
  color: var(--accent); background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent-border);
}
.plv__title {
  font-size: var(--text-2xl); font-weight: 700; letter-spacing: -0.02em;
  color: var(--text-primary); margin-top: 3px;
}
.plv__head-actions { display: flex; align-items: center; gap: 12px; }

/* Stat pill */
.plv__stat-pill {
  display: flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: var(--text-sm); font-variant-numeric: tabular-nums;
}
.plv__stat-num { font-weight: 700; color: var(--accent-text); }
.plv__stat-sep { color: var(--text-muted); }
.plv__stat-total { color: var(--text-tertiary); }
.plv__stat-label { font-family: var(--font-sans); font-size: var(--text-xs); color: var(--text-tertiary); }

/* Toolbar */
.plv__toolbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

/* Loading */
.plv__loading {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  padding: 48px; color: var(--text-tertiary); font-size: var(--text-sm);
}
@keyframes plv-spin { to { transform: rotate(360deg); } }
.plv__spin { animation: plv-spin 0.7s linear infinite; }

/* Table */
.plv__table { width: 100%; border-collapse: collapse; }
.plv__table th {
  padding: 10px 14px; text-align: left;
  font-size: var(--text-xs); font-weight: 600; color: var(--text-tertiary);
  text-transform: uppercase; letter-spacing: var(--tracking-wider);
  border-bottom: 1px solid var(--border-subtle);
}
.plv__table td {
  padding: 10px 14px; font-size: var(--text-sm);
  color: var(--text-primary); border-bottom: 1px solid var(--border-subtle);
}
.plv__table tbody tr:last-child td { border-bottom: 0; }
.plv__table tbody tr:hover td { background: var(--surface-hover); }
.plv__th-right { text-align: right; }
.plv__td-right { text-align: right; }
.plv__plugin-name { font-weight: 500; }
.plv__mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--text-xs) !important; color: var(--text-secondary) !important; }
.plv__secondary { color: var(--text-secondary) !important; }
.plv__wipe-cell { font-size: var(--text-xs) !important; }
.plv__row-actions { display: flex; align-items: center; justify-content: flex-end; gap: 2px; }

/* Browse */
.plv__browse-meta { font-size: var(--text-xs); color: var(--text-tertiary); font-family: var(--font-mono); }
.plv__browse-name { font-size: var(--text-sm); font-weight: 500; color: var(--text-primary); }
.plv__browse-desc {
  font-size: var(--text-xs); color: var(--text-tertiary); margin-top: 2px;
  max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.plv__browse-foot {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 14px; border-top: 1px solid var(--border-subtle);
}
.plv__browse-pag { display: flex; gap: 8px; }

/* Upload */
.plv__upload-wrap { display: flex; flex-direction: column; gap: 12px; }

.plv__dropzone {
  border: 2px dashed var(--border-default); border-radius: var(--radius-md);
  padding: 40px 24px; text-align: center;
  cursor: pointer; transition: var(--transition-colors);
  display: flex; flex-direction: column; align-items: center; gap: 6px;
}
.plv__dropzone:hover { border-color: var(--accent-border); background: var(--accent-soft); }
.plv__dropzone--active { border-color: var(--accent); background: var(--accent-soft); }
.plv__dropzone--ready { border-color: var(--status-online-border); background: var(--status-online-soft); }

.plv__file-hidden { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; }

.plv__drop-icon {
  width: 46px; height: 46px; border-radius: var(--radius-lg);
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-raised-2); color: var(--text-tertiary);
  box-shadow: var(--ring-default); margin-bottom: 4px;
}
.plv__drop-label { font-size: var(--text-sm); font-weight: 600; color: var(--text-primary); }
.plv__drop-hint { font-size: var(--text-xs); color: var(--text-tertiary); }

.plv__file-row { display: flex; align-items: center; gap: 12px; }
.plv__file-icon {
  width: 40px; height: 40px; flex: none; border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center;
  background: var(--status-online-soft); color: var(--status-online);
  box-shadow: inset 0 0 0 1px var(--status-online-border);
}
.plv__file-name { font-size: var(--text-sm); font-weight: 500; color: var(--text-primary); }
.plv__file-size { font-size: var(--text-xs); color: var(--text-tertiary); font-family: var(--font-mono); }

.plv__upload-actions { display: flex; align-items: center; gap: 10px; margin-top: 16px; }
</style>
