<template>
  <div>
    <div class="page-header">
      <h2>{{ isEdit ? 'Edit Printer' : 'New Printer' }}</h2>
    </div>

    <div class="card">
      <div v-if="loading" class="loading">Loading...</div>

      <form v-else @submit.prevent="savePrinter">
        <div class="form-row">
          <div class="form-group">
            <label for="machinenumber">Windows Name *</label>
            <input
              id="machinenumber"
              v-model="form.machinenumber"
              type="text"
              class="form-control"
              required
              @input="onWindowsNameInput"
              :class="{ 'auto-generated': !manualWindowsName && form.machinenumber }"
            />
            <small class="form-hint">Auto-generated from CSF Name, Alias, Vendor & Model</small>
          </div>

          <div class="form-group">
            <label for="alias">Alias / Location</label>
            <input
              id="alias"
              v-model="form.alias"
              type="text"
              class="form-control"
              placeholder="e.g., SpoolsInspection"
            />
            <small class="form-hint">Used in Windows name generation</small>
          </div>
        </div>

        <div class="form-row">
          <div class="form-group" v-if="isEnabled('fqdn', 'printer')">
            <label for="hostname">Hostname (FQDN)</label>
            <input
              id="hostname"
              v-model="form.hostname"
              type="text"
              class="form-control"
              @input="onHostnameInput"
              :class="{ 'auto-generated': !manualHostname && form.hostname }"
            />
            <small class="form-hint">Auto-generated from IP address</small>
          </div>

          <div class="form-group">
            <label for="serialnumber">Serial Number</label>
            <input
              id="serialnumber"
              v-model="form.serialnumber"
              type="text"
              class="form-control"
            />
          </div>
        </div>

        <div class="form-row" v-if="isEnabled('gaugelabreference', 'printer') || isEnabled('maintenancereference', 'printer')">
          <div class="form-group" v-if="isEnabled('gaugelabreference', 'printer')">
            <label for="gaugelabreference">Gauge Lab Reference</label>
            <input
              id="gaugelabreference"
              v-model="form.gaugelabreference"
              type="text"
              class="form-control"
            />
          </div>

          <div class="form-group" v-if="isEnabled('maintenancereference', 'printer')">
            <label for="maintenancereference">Maintenance Reference</label>
            <input
              id="maintenancereference"
              v-model="form.maintenancereference"
              type="text"
              class="form-control"
            />
          </div>
        </div>

        <div class="form-row">
          <div class="form-group">
            <label for="machinetypeid">Printer Type *</label>
            <select
              id="machinetypeid"
              v-model="form.machinetypeid"
              class="form-control"
              required
              @change="form.modelnumberid = ''"
            >
              <option value="">Select type...</option>
              <option
                v-for="pt in printerTypes"
                :key="pt.printertypeid"
                :value="pt.printertypeid"
              >
                {{ pt.printertype }}
              </option>
            </select>
          </div>

          <div class="form-group">
            <label for="statusid">Status</label>
            <select
              id="statusid"
              v-model="form.statusid"
              class="form-control"
            >
              <option value="">Select status...</option>
              <option
                v-for="s in statuses"
                :key="s.statusid"
                :value="s.statusid"
              >
                {{ s.status }}
              </option>
            </select>
          </div>
        </div>

        <div class="form-row">
          <div class="form-group">
            <label for="vendorid">Vendor</label>
            <select
              id="vendorid"
              v-model="form.vendorid"
              class="form-control"
              @change="form.modelnumberid = ''"
            >
              <option value="">Select vendor...</option>
              <option
                v-for="v in vendors"
                :key="v.vendorid"
                :value="v.vendorid"
              >
                {{ v.vendor }}
              </option>
            </select>
          </div>

          <div class="form-group">
            <label for="modelnumberid">Model *</label>
            <select
              id="modelnumberid"
              v-model="form.modelnumberid"
              class="form-control"
              :disabled="!form.vendorid"
              required
            >
              <option value="">{{ form.vendorid ? 'Select model...' : 'Select a vendor first' }}</option>
              <option
                v-for="m in filteredModels"
                :key="m.modelnumberid"
                :value="m.modelnumberid"
              >
                {{ m.modelnumber }}
              </option>
            </select>
            <small v-if="!form.vendorid" class="form-hint">
              Select a vendor first to choose a model
            </small>
          </div>
        </div>

        <div class="form-group">
          <label for="locationid">Location</label>
          <select
            id="locationid"
            v-model="form.locationid"
            class="form-control"
          >
            <option value="">Select location...</option>
            <option
              v-for="l in locations"
              :key="l.locationid"
              :value="l.locationid"
            >
              {{ l.locationname }}
            </option>
          </select>
        </div>

        <!-- Printer-specific fields -->
        <h4 style="margin-top: 1.5rem; margin-bottom: 1rem;">Printer Settings</h4>

        <div class="form-row">
          <div class="form-group">
            <label for="ipaddress">IP Address</label>
            <input
              id="ipaddress"
              v-model="form.ipaddress"
              type="text"
              class="form-control"
              placeholder="e.g., 192.168.1.100"
            />
          </div>

          <div class="form-group">
            <label for="csfname">CSF Name</label>
            <input
              id="csfname"
              v-model="form.csfname"
              type="text"
              class="form-control"
            />
          </div>
        </div>

        <div class="form-row">
          <div class="form-group">
            <label for="pin">PIN</label>
            <input
              id="pin"
              v-model="form.pin"
              type="text"
              class="form-control"
            />
          </div>
        </div>

        <div class="form-group">
          <label for="installpath">Driver Install Path</label>
          <input
            id="installpath"
            v-model="form.installpath"
            type="text"
            class="form-control"
            placeholder="Leave empty for universal driver"
          />
        </div>

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

        <!-- Map Location Picker -->
        <div class="form-group">
          <label>Map Location</label>
          <div class="map-location-control">
            <div v-if="form.mapx !== null && form.mapy !== null" class="current-position">
              Position: {{ form.mapx }}, {{ form.mapy }}
                <span v-if="form.levelid" class="position-level">on {{ levelName(form.levelid) }}</span>
                <span v-else class="position-level position-level-missing">level not set</span>
              <button type="button" class="btn btn-sm btn-secondary" @click="clearMapPosition">Clear</button>
            </div>
            <button type="button" class="btn btn-secondary" @click="openMapPicker">
              Set Location on Map
            </button>
          </div>
        </div>

        <!-- Map Picker Modal -->
        <Modal v-model="showMapPicker" title="Select Location on Map" size="fullscreen">
          <div class="map-modal-content">
            <div v-if="levelOptions().length > 1" class="map-level-picker">
              <label>Level</label>
              <select v-model.number="pickerLevelId" class="form-control">
                <option v-for="option in levelOptions()" :key="option.levelid"
                        :value="option.levelid">{{ option.label }}</option>
              </select>
              <span class="input-hint">
                The position is pixels on this drawing, so pick the level first.
              </span>
            </div>
            <ShopFloorMap
              :pickerMode="true"
              :levelid="pickerLevelId"
              :initialPosition="form.mapx !== null ? { left: form.mapx, top: form.mapy } : null"
              :theme="currentTheme"
              @positionPicked="handlePositionPicked"
            />
          </div>
          <template #footer>
            <button class="btn btn-secondary" @click="showMapPicker = false">Cancel</button>
            <button class="btn btn-primary" @click="confirmMapPosition">Confirm Location</button>
          </template>
        </Modal>

        <!-- Site-defined custom fields for printers -->
        <CustomFieldsInputs ref="customFieldsRef" :assettypeid="PRINTER_ASSETTYPEID" :assetid="currentAssetId" />

        <div v-if="error" class="error-message">{{ error }}</div>

        <div style="display: flex; gap: 0.5rem; margin-top: 1.5rem;">
          <button type="submit" class="btn btn-primary" :disabled="saving">
            {{ saving ? 'Saving...' : 'Save Printer' }}
          </button>
          <router-link to="/printers" class="btn btn-secondary">Cancel</router-link>
        </div>
      </form>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, computed, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { assetsApi, vendorsApi, locationsApi, printersApi, modelsApi } from '@/api'
import ShopFloorMap from '@/components/ShopFloorMap.vue'
import { loadMapConfig, levelOptions, levelName, state as mapConfig }
  from '@/composables/mapConfig'
import Modal from '@/components/Modal.vue'
import CustomFieldsInputs from '@/components/CustomFieldsInputs.vue'
import { currentTheme } from '@/stores/theme'
import { useIdentifierFlags } from '@/composables/identifierSettings'
import { apiError } from '@/utils/apiError'
import { getPrinterHostnameTemplate } from '@/utils/siteSettings'

const { isEnabled } = useIdentifierFlags()

const route = useRoute()
const router = useRouter()

const isEdit = computed(() => !!route.params.id)

// Seeded asset-type id for printers (see /api/assets/types).
const PRINTER_ASSETTYPEID = 4
const customFieldsRef = ref(null)
const currentAssetId = ref(null)
const manualHostname = ref(false)
const manualWindowsName = ref(false)

const loading = ref(true)
const saving = ref(false)
const error = ref('')
const showMapPicker = ref(false)
// Which drawing the picker shows, and therefore which level the coordinates it
// returns belong to (ADR-017). Opens on the position's existing level so editing
// a marker does not silently move it to the default one.
const pickerLevelId = ref(null)
const tempMapPosition = ref(null)

const form = ref({
  machinenumber: '',
  alias: '',
  hostname: '',
  serialnumber: '',
  gaugelabreference: '',
  maintenancereference: '',
  machinetypeid: '',
  statusid: '',
  vendorid: '',
  modelnumberid: '',
  locationid: '',
  notes: '',
  mapx: null,
  mapy: null,
  levelid: null,
  // Printer-specific
  ipaddress: '',
  csfname: '',
  installpath: '',
  pin: ''
})

const printerTypes = ref([])
const statuses = ref([])
const vendors = ref([])
const models = ref([])
const locations = ref([])

// Filter models by selected vendor and printer type
const filteredModels = computed(() => {
  return models.value.filter(m => {
    // Filter by vendor if selected
    if (form.value.vendorid && m.vendorid !== form.value.vendorid) {
      return false
    }
    // Filter by printer type if selected, but only exclude models that have a
    // type set and it differs. Most models have no machinetypeid, so excluding
    // null-typed models would hide the printer's own model from the dropdown.
    if (form.value.machinetypeid && m.machinetypeid && m.machinetypeid !== form.value.machinetypeid) {
      return false
    }
    return true
  })
})

// Get short description from model number for naming
function getModelShortDesc(modelNumber) {
  if (!modelNumber) return ''
  const mn = modelNumber.toLowerCase()

  if (mn.includes('colorlaserjet')) return 'ColorLaserJet'
  if (mn.includes('laserjetpro') || mn.includes('laserjet pro')) return 'LaserJetPro'
  if (mn.includes('laserjet')) return 'LaserJet'
  if (mn.includes('altalink')) return 'Altalink'
  if (mn.includes('versalink')) return 'Versalink'
  if (mn.includes('designjet')) return 'DesignJet'
  if (mn.includes('dtc')) return 'DTC'
  if (mn.includes('officejet')) return 'OfficeJet'
  if (mn.includes('pagewide')) return 'PageWide'

  // Fallback: get letters before first digit
  const match = modelNumber.match(/^([A-Za-z]+)/)
  return match ? match[1] : modelNumber.substring(0, 5)
}

// Auto-generate hostname from IP address using the site template ({ip} =
// dash-separated IP).
async function generateHostname(ip) {
  if (!ip) return ''
  const ipDashed = ip.replace(/\./g, '-')
  const template = await getPrinterHostnameTemplate()
  return template.replace('{ip}', ipDashed)
}

// Auto-generate Windows name (machinenumber)
function generateWindowsName() {
  const parts = []

  // 1. CSF Name (if set and not "NONE")
  const csfName = form.value.csfname?.trim()
  if (csfName && csfName.toUpperCase() !== 'NONE') {
    parts.push(csfName.replace(/\s+/g, ''))
  }

  // 2. Location (from alias, removing spaces and "Machine")
  const alias = form.value.alias?.trim()
  if (alias) {
    const location = alias.replace(/\s+/g, '').replace(/Machine/gi, '')
    // Skip if same as CSF name
    if (location.toLowerCase() !== csfName?.toLowerCase()) {
      parts.push(location)
    }
  }

  // 3. Vendor + Model short description
  const selectedModel = models.value.find(m => m.modelnumberid === form.value.modelnumberid)
  const selectedVendor = vendors.value.find(v => v.vendorid === form.value.vendorid)

  let vendorModel = ''
  if (selectedVendor) {
    vendorModel = selectedVendor.vendor.replace(/\s+/g, '')
  }
  if (selectedModel) {
    vendorModel += getModelShortDesc(selectedModel.modelnumber)
  }
  if (vendorModel) {
    parts.push(vendorModel)
  }

  return parts.join('-')
}

// Watch IP address and auto-generate hostname
watch(() => form.value.ipaddress, async (newIp) => {
  if (!manualHostname.value && newIp) {
    form.value.hostname = await generateHostname(newIp)
  }
})

// Watch fields that affect Windows name generation
watch(
  () => [form.value.csfname, form.value.alias, form.value.vendorid, form.value.modelnumberid],
  () => {
    if (!manualWindowsName.value && !isEdit.value) {
      const generated = generateWindowsName()
      if (generated) {
        form.value.machinenumber = generated
      }
    }
  }
)

// Track manual edits to hostname
function onHostnameInput() {
  manualHostname.value = true
}

// Track manual edits to Windows name
function onWindowsNameInput() {
  manualWindowsName.value = true
}

onMounted(async () => {
  try {
    // Load reference data (models paged in full via listAll, see api/index.js)
    // perpage 100 so dropdowns aren't truncated to the default 20-row page
    // (e.g. 44 vendors; the editing record's vendor can be past row 20)
    const [mtRes, statusRes, vendorRes, allModels, locRes] = await Promise.all([
      printersApi.types.list({ perpage: 100 }),
      assetsApi.statuses.list(),
      vendorsApi.list({ perpage: 100 }),
      modelsApi.listAll(),
      locationsApi.list({ perpage: 100 })
    ])

    printerTypes.value = mtRes.data.data || []
    statuses.value = statusRes.data.data || []
    vendors.value = vendorRes.data.data || []
    models.value = allModels
    locations.value = locRes.data.data || []

    // Load printer if editing
    if (isEdit.value) {
      const response = await printersApi.get(route.params.id)
      const printer = response.data.data
      currentAssetId.value = printer.assetid || null
      // asset-based shape: printer extension fields live under printer.printer
      const ext = printer.printer || {}

      // Get IP from communications
      const primaryComm = printer.communications?.find(c => c.isprimary) || printer.communications?.[0]

      form.value = {
        // "Windows Name" is the printer's business identifier (assetnumber).
        // Prefer the explicit windowsname, then fall back to assetnumber.
        machinenumber: ext.windowsname || printer.assetnumber || '',
        alias: printer.name && printer.name.toUpperCase() !== 'NONE' ? printer.name : '',
        hostname: ext.hostname || '',
        serialnumber: printer.serialnumber || '',
        gaugelabreference: printer.gaugelabreference || '',
        maintenancereference: printer.maintenancereference || '',
        machinetypeid: ext.printertypeid || '',
        statusid: printer.statusid || '',
        vendorid: ext.vendorid || '',
        modelnumberid: ext.modelnumberid || '',
        locationid: printer.locationid || '',
        notes: printer.notes || '',
        mapx: printer.mapx ?? null,
        mapy: printer.mapy ?? null,
        levelid: printer.levelid ?? null,
        // Printer-specific
        ipaddress: primaryComm?.ipaddress || '',
        csfname: ext.sharename || '',
        installpath: ext.installpath || '',
        pin: ext.pin || ''
      }

      // Don't auto-generate for existing printers
      manualWindowsName.value = true
      manualHostname.value = true
    }
  } catch (err) {
    console.error('Error loading data:', err)
    error.value = 'Failed to load data'
  } finally {
    loading.value = false
  }
})

function handlePositionPicked(position) {
  tempMapPosition.value = position
}

function openMapPicker() {
  loadMapConfig().then(() => {
    pickerLevelId.value = form.value.levelid || mapConfig.defaultlevelid
    showMapPicker.value = true
  })
}

function confirmMapPosition() {
  if (tempMapPosition.value) {
    form.value.mapx = tempMapPosition.value.left
    form.value.mapy = tempMapPosition.value.top
    // Never one without the other: coordinates saved with no level render as
    // "level unknown", and coordinates saved against the wrong level render
    // convincingly in the wrong place.
    form.value.levelid = pickerLevelId.value
  }
  showMapPicker.value = false
}

function clearMapPosition() {
  form.value.mapx = null
  form.value.mapy = null
  form.value.levelid = null
  tempMapPosition.value = null
}

async function savePrinter() {
  error.value = ''

  // Model is required. The native `required` on the select is skipped while it
  // is disabled (no vendor picked), so guard here too and point at the vendor.
  if (!form.value.modelnumberid) {
    error.value = form.value.vendorid
      ? 'Model is required.'
      : 'Select a vendor, then a model (model is required).'
    return
  }

  saving.value = true

  try {
    // One payload for the printers plugin, which owns asset core + extension +
    // primary communication. The "Windows Name" field is the business
    // identifier, written to both assetnumber and the extension windowsname.
    const payload = {
      assetnumber: form.value.machinenumber,
      windowsname: form.value.machinenumber || null,
      hostname: form.value.hostname || null,
      serialnumber: form.value.serialnumber || null,
      gaugelabreference: form.value.gaugelabreference || null,
      maintenancereference: form.value.maintenancereference || null,
      printertypeid: form.value.machinetypeid || null,
      statusid: form.value.statusid || null,
      vendorid: form.value.vendorid || null,
      modelnumberid: form.value.modelnumberid || null,
      locationid: form.value.locationid || null,
      sharename: form.value.csfname || null,
      iscsf: !!form.value.csfname,
      installpath: form.value.installpath || null,
      pin: form.value.pin || null,
      ipaddress: form.value.ipaddress || null,
      mapx: form.value.mapx,
      mapy: form.value.mapy
    }
    // only set the display name when an alias is given, so we don't clobber it
    if (form.value.alias) {
      payload.name = form.value.alias
    }

    let assetId = currentAssetId.value
    if (isEdit.value) {
      const response = await printersApi.update(route.params.id, payload)
      assetId = assetId || response.data?.data?.assetid || response.data?.data?.asset?.assetid
    } else {
      const response = await printersApi.create(payload)
      assetId = response.data?.data?.assetid || response.data?.data?.asset?.assetid
    }

    if (assetId && customFieldsRef.value) {
      try {
        await customFieldsRef.value.save(assetId)
      } catch (cfErr) {
        console.error('Error saving custom fields:', cfErr)
      }
    }

    router.push('/printers')
  } catch (err) {
    console.error('Error saving printer:', err)
    error.value = apiError(err, 'Failed to save printer')
  } finally {
    saving.value = false
  }
}
</script>

<style scoped>
.map-location-control {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.current-position {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-family: monospace;
  color: var(--text);
}

.map-modal-content {
  height: calc(90vh - 140px);
}

.map-modal-content :deep(.shopfloor-map) {
  height: 100%;
}

.map-modal-content :deep(.map-container) {
  height: calc(100% - 50px);
}

.form-hint {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.8rem;
  color: var(--text-light, #666);
}

/* auto-fill cue: a subtle translucent blue tint + accent border that reads
   correctly over both light and dark backgrounds. Text color stays themed
   (no solid light fill that turns into an unreadable white box in dark mode). */
.auto-generated {
  background-color: rgba(33, 150, 243, 0.12);
  border-color: #90caf9;
}
</style>
