<template>
  <div>
    <div class="page-header">
      <h2>Warranties</h2>
      <div class="header-actions">
        <button class="btn btn-secondary" :disabled="syncing" @click="syncDell(false)">
          {{ syncing ? 'Syncing Dell...' : 'Sync Dell' }}
        </button>
        <button class="btn btn-secondary" :disabled="syncing" @click="syncDell(true)"
                title="Re-check every Dell warranty, including ones already dated">
          Re-check all
        </button>
        <button class="btn btn-primary" @click="openModal()">+ Add Warranty</button>
      </div>
    </div>

    <div class="filters">
      <label>Status
        <select v-model="statusFilter" class="form-control" @change="loadData">
          <option value="">All</option>
          <option value="active">Active</option>
          <option value="expiring">Expiring Soon</option>
          <option value="expired">Expired</option>
          <option value="unknown">Unknown</option>
        </select>
      </label>
      <input v-model="search" type="text" class="form-control" placeholder="Search vendor, service level, tag, asset..." />
      <span class="result-count">{{ filteredItems.length }} of {{ items.length }}</span>
    </div>

    <div class="card">
      <div v-if="loading" class="muted">Loading...</div>
      <template v-else>
        <div class="table-container">
          <table>
            <thead>
              <tr>
                <th>Vendor</th>
                <th>Status</th>
                <th>Service Level</th>
                <th>Ends</th>
                <th>Covers</th>
                <th>Machine #</th>
                <th>Actions</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="w in paginatedItems" :key="w.warrantyid">
                <td><strong>{{ w.vendor }}</strong><span v-if="w.provider !== 'manual'" class="muted"> ({{ w.provider }})</span></td>
                <td><span class="status-badge" :style="colorStyle(w.statuscolor)">{{ statusLabel(w.status) }}</span></td>
                <td class="servicelevel-cell" :title="w.servicelevel">{{ w.servicelevel || '-' }}</td>
                <td>{{ w.enddate ? formatDate(w.enddate) : '-' }}</td>
                <td>
                  <span v-if="!w.assets.length" class="muted">-</span>
                  <router-link v-for="a in w.assets" :key="a.assetid" :to="assetLink(a)" class="asset-chip" :title="a.name || a.assetnumber">{{ a.assetnumber }}</router-link>
                </td>
                <td>
                  <template v-for="a in w.assets" :key="`m-${a.assetid}`">
                    <MachineMapChip v-if="a.machine" :machine="a.machine" />
                  </template>
                  <span v-if="!w.assets.some(a => a.machine)" class="muted">-</span>
                </td>
                <td class="actions">
                  <button v-if="w.provider !== 'manual'" class="btn btn-secondary btn-sm" @click="refresh(w)">Refresh</button>
                  <button class="btn btn-secondary btn-sm" @click="openModal(w)">Edit</button>
                  <button class="btn btn-danger btn-sm" @click="deleteWarranty(w)">Delete</button>
                </td>
              </tr>
              <tr v-if="filteredItems.length === 0">
                <td colspan="6" style="text-align: center; color: var(--text-light);">No warranties</td>
              </tr>
            </tbody>
          </table>
        </div>

        <div v-if="totalPages > 1" class="pagination">
          <button class="btn btn-secondary btn-sm" :disabled="page === 1" @click="page--">Prev</button>
          <span class="page-info">Page {{ page }} of {{ totalPages }}</span>
          <button class="btn btn-secondary btn-sm" :disabled="page === totalPages" @click="page++">Next</button>
        </div>
      </template>
    </div>

    <div v-if="showModal" class="modal-overlay">
      <div class="modal">
        <div class="modal-header"><h3>{{ editing ? 'Edit' : 'Add' }} Warranty</h3></div>
        <form @submit.prevent="save">
          <div class="modal-body">
            <div class="form-row">
              <div class="form-group">
                <label>Vendor *</label>
                <select v-model="form.vendor" class="form-control" required>
                  <option value="" disabled>Select a vendor...</option>
                  <option v-for="name in vendorOptions" :key="name" :value="name">{{ name }}</option>
                </select>
                <small class="muted">Who backs the warranty. Manage the list under Vendors.</small>
              </div>
              <div class="form-group">
                <label>Lookup source</label>
                <select v-model="form.provider" class="form-control">
                  <option value="manual">Manual entry</option>
                  <option value="dell">Dell (auto-refresh)</option>
                  <option value="lenovo">Lenovo (auto-refresh)</option>
                  <option value="hp">HP (auto-refresh)</option>
                </select>
                <small class="muted">Where coverage data comes from. Non-manual sources can be refreshed from the maker's warranty API.</small>
              </div>
            </div>
            <div class="form-row">
              <div class="form-group">
                <label>Service Tag / Serial</label>
                <input v-model="form.servicetag" type="text" class="form-control" maxlength="100" />
              </div>
              <div class="form-group">
                <label>Service Level</label>
                <input v-model="form.servicelevel" type="text" class="form-control" maxlength="150" />
              </div>
            </div>
            <div class="form-row">
              <div class="form-group">
                <label>Start Date</label>
                <input v-model="form.startdate" type="date" class="form-control" />
              </div>
              <div class="form-group">
                <label>End Date</label>
                <input v-model="form.enddate" type="date" class="form-control" />
              </div>
            </div>

            <div class="form-group">
              <label>Covered Assets</label>
              <div class="asset-search">
                <input v-model="assetQuery" type="text" class="form-control" placeholder="Search asset number or name..."
                       @input="searchAssets" />
                <ul v-if="assetResults.length" class="asset-results">
                  <li v-for="a in assetResults" :key="a.assetid" @click="addAsset(a)">
                    {{ a.assetnumber }}<span v-if="a.name" class="muted"> - {{ a.name }}</span>
                  </li>
                </ul>
              </div>
              <div class="asset-chips">
                <span v-for="a in selectedAssets" :key="a.assetid" class="asset-chip removable">
                  {{ a.assetnumber }}
                  <button type="button" @click="removeAsset(a)">x</button>
                </span>
                <span v-if="!selectedAssets.length" class="muted">None linked</span>
              </div>
            </div>

            <div class="form-group">
              <label>Notes</label>
              <textarea v-model="form.notes" class="form-control" rows="2"></textarea>
            </div>

            <div class="form-group">
              <label>Proof of cover</label>
              <div v-if="proofName" class="proof-current">
                <a v-if="proofUrl" :href="proofUrl" @click.prevent="downloadProof">{{ proofName }}</a>
                <span v-else>{{ proofName }}</span>
                <button type="button" class="btn btn-sm btn-secondary" @click="removeProof"
                        :disabled="busyProof">Remove</button>
              </div>
              <input type="file" class="form-control" :accept="PROOF_ACCEPT" @change="onProofPicked" />
              <small class="muted">
                Invoice, certificate or a saved email - up to 25MB. Downloading
                needs a login, since it carries pricing and a service tag.
              </small>
            </div>
            <div v-if="error" class="error-message">{{ error }}</div>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" @click="closeModal">Cancel</button>
            <button type="submit" class="btn btn-primary" :disabled="saving">{{ saving ? 'Saving...' : 'Save' }}</button>
          </div>
        </form>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { colorStyle } from '@/utils/colorStyle'
import api, { warrantyApi, assetsApi, vendorsApi } from '@/api'
import { useToast } from '@/composables/toast'
import { apiError } from '@/utils/apiError'
import MachineMapChip from '../components/MachineMapChip.vue'

const toast = useToast()
const route = useRoute()

const items = ref([])
const loading = ref(true)
const syncing = ref(false)
const search = ref('')
const page = ref(1)
const perPage = 25

// Client-side search across vendor / service level / tag / linked asset numbers.
const filteredItems = computed(() => {
  const term = search.value.trim().toLowerCase()
  if (!term) return items.value
  return items.value.filter(w =>
    (w.vendor || '').toLowerCase().includes(term) ||
    (w.servicelevel || '').toLowerCase().includes(term) ||
    (w.servicetag || '').toLowerCase().includes(term) ||
    (w.assets || []).some(a => (a.assetnumber || '').toLowerCase().includes(term)))
})
const totalPages = computed(() => Math.max(1, Math.ceil(filteredItems.value.length / perPage)))
const paginatedItems = computed(() => filteredItems.value.slice((page.value - 1) * perPage, page.value * perPage))

// Reset to page 1 whenever the filtered set changes.
watch([filteredItems, () => filteredItems.value.length], () => {
  if (page.value > totalPages.value) page.value = 1
})
watch(search, () => { page.value = 1 })
const statusFilter = ref('')
const showModal = ref(false)
const editing = ref(null)
const saving = ref(false)
const error = ref('')
const form = ref(blankForm())
const selectedAssets = ref([])
const assetQuery = ref('')
const assetResults = ref([])
// Vendor dropdown options, pulled from the site vendor catalog.
const vendorNames = ref([])
// Keep an existing warranty's vendor selectable even if it is not (or no longer)
// in the catalog, so editing never silently blanks it.
const vendorOptions = computed(() => {
  const current = (form.value.vendor || '').trim()
  if (current && !vendorNames.value.includes(current)) return [current, ...vendorNames.value]
  return vendorNames.value
})

function blankForm() {
  return { vendor: '', provider: 'manual', servicetag: '', servicelevel: '', startdate: '', enddate: '', notes: '' }
}

function statusLabel(status) {
  return { active: 'Active', expiring: 'Expiring Soon', expired: 'Expired', unknown: 'Unknown' }[status] || status
}
function formatDate(d) { return new Date(d + 'T00:00:00').toLocaleDateString() }

// Route to the right detail page by asset type.
function assetLink(a) {
  const map = { computer: '/pcs/', printer: '/printers/', network_device: '/network/', machine: '/machines/', measuring_tool: '/measuringtools/by-asset/' }
  const base = map[a.assettypename] || '/assets/'
  return base + a.assetid
}

onMounted(async () => {
  await loadData()
  loadVendors()
  // Deep-link from an asset detail page: open the add modal pre-linked to it.
  const addfor = route.query.addfor
  if (addfor) {
    openModal()
    try {
      const response = await assetsApi.get(addfor)
      const asset = response.data.data
      if (asset) selectedAssets.value = [{ assetid: asset.assetid, assetnumber: asset.assetnumber }]
    } catch (err) {
      selectedAssets.value = [{ assetid: Number(addfor), assetnumber: `Asset ${addfor}` }]
    }
  }
})

async function loadVendors() {
  // Best-effort: the combobox still accepts free text if this fails.
  try {
    const response = await vendorsApi.list({ per_page: 1000 })
    const rows = response.data.data
    const list = Array.isArray(rows) ? rows : (rows.items || [])
    vendorNames.value = list.map(v => v.vendor || v.name).filter(Boolean).sort()
  } catch (err) {
    vendorNames.value = []
  }
}

async function loadData() {
  loading.value = true
  try {
    const params = statusFilter.value ? { status: statusFilter.value } : {}
    const response = await warrantyApi.list(params)
    items.value = response.data.data || []
  } catch (err) {
    console.error('Error loading warranties:', err)
  } finally {
    loading.value = false
  }
}

let searchTimer = null
function searchAssets() {
  clearTimeout(searchTimer)
  const q = assetQuery.value.trim()
  if (!q) { assetResults.value = []; return }
  searchTimer = setTimeout(async () => {
    try {
      const response = await assetsApi.search(q, { perpage: 8 })
      assetResults.value = response.data.data || []
    } catch (err) {
      assetResults.value = []
    }
  }, 250)
}

function addAsset(a) {
  if (!selectedAssets.value.some(x => x.assetid === a.assetid)) {
    selectedAssets.value.push({ assetid: a.assetid, assetnumber: a.assetnumber })
  }
  assetQuery.value = ''
  assetResults.value = []
}
function removeAsset(a) {
  selectedAssets.value = selectedAssets.value.filter(x => x.assetid !== a.assetid)
}

function openModal(item = null) {
  editing.value = item
  if (item) {
    form.value = {
      vendor: item.vendor || '', provider: item.provider || 'manual',
      servicetag: item.servicetag || '', servicelevel: item.servicelevel || '',
      startdate: item.startdate || '', enddate: item.enddate || '', notes: item.notes || '',
    }
    selectedAssets.value = (item.assets || []).map(a => ({ assetid: a.assetid, assetnumber: a.assetnumber }))
  } else {
    form.value = blankForm()
    selectedAssets.value = []
    proofName.value = ''
    proofUrl.value = ''
  }
  pendingProof.value = null
  assetQuery.value = ''
  assetResults.value = []
  error.value = ''
  showModal.value = true
}
function closeModal() { showModal.value = false; editing.value = null }

// Chosen before a new warranty exists, so it is held here and uploaded once
// there is an id to attach it to.
const pendingProof = ref(null)
const proofName = ref('')
const proofUrl = ref('')
const busyProof = ref(false)
const PROOF_ACCEPT = '.pdf,.png,.jpg,.jpeg,.gif,.webp,.tif,.tiff,.msg,.eml,.doc,.docx,.xls,.xlsx'
const MAX_PROOF_BYTES = 25 * 1024 * 1024

function onProofPicked(event) {
  const file = event.target.files?.[0]
  if (!file) return
  if (file.size > MAX_PROOF_BYTES) {
    error.value = `${file.name} is ${(file.size / 1048576).toFixed(0)}MB; the limit is 25MB.`
    event.target.value = ''
    return
  }
  error.value = ''
  pendingProof.value = file
  proofName.value = file.name
  proofUrl.value = ''
}

async function removeProof() {
  pendingProof.value = null
  proofName.value = ''
  proofUrl.value = ''
  if (editing.value) {
    busyProof.value = true
    try { await warrantyApi.removeProof(editing.value.warrantyid) }
    catch (err) { error.value = apiError(err, 'Failed to remove the document') }
    finally { busyProof.value = false }
  }
}

// The route is authenticated, so a plain href would 401. Fetch it through the
// client, which carries the token, then hand the blob to the browser.
async function downloadProof() {
  try {
    const response = await api.get(proofUrl.value, { responseType: 'blob' })
    const url = URL.createObjectURL(response.data)
    const link = document.createElement('a')
    link.href = url
    link.download = proofName.value || 'proof'
    link.click()
    URL.revokeObjectURL(url)
  } catch (err) {
    error.value = apiError(err, 'Failed to download the document')
  }
}

async function save() {
  error.value = ''
  saving.value = true
  try {
    const payload = { ...form.value, assetids: selectedAssets.value.map(a => a.assetid) }
    let warrantyid
    if (editing.value) {
      warrantyid = editing.value.warrantyid
      await warrantyApi.update(warrantyid, payload)
    } else {
      const created = await warrantyApi.create(payload)
      warrantyid = created.data.data.warrantyid
    }
    // After the save: a new warranty has no id until it exists, and the upload
    // keys on it. A failed upload leaves the saved record alone and reports.
    if (pendingProof.value) {
      await warrantyApi.uploadProof(warrantyid, pendingProof.value)
      pendingProof.value = null
    }
    closeModal()
    loadData()
  } catch (err) {
    error.value = apiError(err, 'Failed to save')
  } finally {
    saving.value = false
  }
}

async function deleteWarranty(w) {
  if (!confirm(`Delete the ${w.vendor} warranty?`)) return
  try {
    await warrantyApi.remove(w.warrantyid)
    loadData()
  } catch (err) {
    toast.error(apiError(err, 'Failed to delete'))
  }
}

async function syncDell(all = false) {
  syncing.value = true
  toast.info(all ? 'Re-checking all Dell warranties...' : 'Looking up Dell service tags... this can take a moment.')
  try {
    const response = await warrantyApi.syncDell(all)
    const summary = response.data?.data || {}
    loadData()
    toast.success(`Dell sync: ${summary.created || 0} added, ${summary.updated || 0} updated (${summary.matched || 0} tags matched).`)
  } catch (err) {
    toast.error(apiError(err, 'Dell sync failed'))
  } finally {
    syncing.value = false
  }
}

async function refresh(w) {
  try {
    const response = await warrantyApi.refresh(w.warrantyid)
    loadData()
    const updated = response.data?.data
    if (updated) {
      toast.success(`${updated.vendor}: ${updated.servicelevel || 'coverage'} ends ${updated.enddate || 'unknown'}`)
    }
  } catch (err) {
    toast.error(apiError(err, 'Refresh failed'))
  }
}
</script>

<style scoped>
.muted { color: var(--text-light); }
.status-badge { padding: 0.15rem 0.6rem; border-radius: 12px; font-size: 0.78rem; font-weight: 600; }
.filters { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem; }
/* Keep the "Status" label + its select on one line so it aligns with the
   single-line search box next to it. */
.filters label { display: inline-flex; align-items: center; gap: 0.4rem; }
.filters .form-control { max-width: 320px; }
.result-count { color: var(--text-light); font-size: 0.85rem; }
.proof-current { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.5rem; }
.proof-current a { word-break: break-all; }
.servicelevel-cell { max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pagination { display: flex; align-items: center; justify-content: center; gap: 1rem; padding: 0.9rem 0 0.2rem; }
.page-info { color: var(--text-light); font-size: 0.85rem; }
.form-row { display: flex; gap: 1rem; }
.form-row .form-group { flex: 1; }
.asset-search { position: relative; }
.asset-results {
  position: absolute; z-index: 10; left: 0; right: 0; margin: 2px 0 0;
  padding: 0; list-style: none; background: var(--bg-card-solid);
  border: 1px solid var(--border); border-radius: 6px; max-height: 200px; overflow-y: auto;
}
.asset-results li { padding: 0.45rem 0.6rem; cursor: pointer; }
.asset-results li:hover { background: var(--bg); }
.asset-chips { margin-top: 0.5rem; display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
.asset-chip {
  display: inline-flex; align-items: center; gap: 0.3rem;
  padding: 0.15rem 0.55rem; margin: 0 0.25rem 0.25rem 0;
  background: var(--bg); border-radius: 12px; font-size: 0.8rem; text-decoration: none; color: var(--text);
}
.asset-chip.removable button {
  border: none; background: none; color: var(--text-light); cursor: pointer; font-size: 0.85rem; padding: 0;
}
</style>
