<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 'Catalyst'
    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 re-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>
