<template>
  <div>
    <div class="page-header">
      <h2>{{ isEdit ? 'Edit Network Device' : 'Add Network Device' }}</h2>
    </div>

    <div class="card form-card">
      <form @submit.prevent="submitForm">
        <!-- Asset Information -->
        <fieldset>
          <legend>Asset Information</legend>

          <div class="form-row">
            <div class="form-group">
              <!-- Not required on create: left blank it is generated from the
                   device type's prefix and the name (AP-<name>). An explicit
                   value always wins, because a device carrying a real
                   identifier - vendor tag, controller name, serial - should
                   keep it. Still locked on edit: other records join on this. -->
              <label for="assetnumber">Asset Number<span v-if="isEdit"> *</span></label>
              <input
                id="assetnumber"
                v-model="form.assetnumber"
                type="text"
                class="form-control"
                :required="isEdit"
                :disabled="isEdit && !assetNumberMissing"
                :placeholder="generatedAssetNumber || 'leave blank to generate from the name'"
              />
              <!-- Locked while editing, because an asset number is identity and
                   changing it silently re-keys the record. The exception is a
                   record that HAS no number: those exist (an update path used to
                   accept a blank), the server now rejects a blank on save, and
                   with the field disabled there was no way to supply one - the
                   row could not be saved at all until it was fixed elsewhere. -->
              <small class="form-hint" v-if="assetNumberMissing">
                This device has no asset number. Give it one to save.
              </small>
              <small class="form-hint" v-if="!isEdit && !form.assetnumber && generatedAssetNumber">
                Will be created as <code>{{ generatedAssetNumber }}</code>
              </small>
            </div>
            <div class="form-group">
              <label for="name">Name</label>
              <input
                id="name"
                v-model="form.name"
                type="text"
                class="form-control"
              />
            </div>
          </div>

          <div class="form-row">
            <div class="form-group">
              <label for="serialnumber">Serial Number</label>
              <input
                id="serialnumber"
                v-model="form.serialnumber"
                type="text"
                class="form-control"
              />
            </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" v-if="isEnabled('gaugelabreference', 'network_device') || isEnabled('maintenancereference', 'network_device')">
            <div class="form-group" v-if="isEnabled('gaugelabreference', 'network_device')">
              <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', 'network_device')">
              <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="locationid">Location</label>
              <select id="locationid" v-model="form.locationid" class="form-control">
                <option value="">Select Location</option>
                <option v-for="loc in locations" :key="loc.locationid" :value="loc.locationid">
                  {{ loc.locationname }}
                </option>
              </select>
            </div>
            <div class="form-group">
              <label for="businessunitid">Business Unit</label>
              <select id="businessunitid" v-model="form.businessunitid" class="form-control">
                <option value="">Select Business Unit</option>
                <option v-for="bu in businessUnits" :key="bu.businessunitid" :value="bu.businessunitid">
                  {{ bu.businessunit }}
                </option>
              </select>
            </div>
          </div>
        </fieldset>

        <!-- Network Device Information -->
        <fieldset>
          <legend>Network Device Details</legend>

          <div class="form-row">
            <div class="form-group">
              <label for="hostname">Hostname</label>
              <input
                id="hostname"
                v-model="form.hostname"
                type="text"
                class="form-control"
                placeholder="e.g., sw-bldg1-floor2"
              />
            </div>
            <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.10"
              />
            </div>
            <div class="form-group">
              <label for="networkdevicetypeid">Device Type</label>
              <select id="networkdevicetypeid" v-model="form.networkdevicetypeid" class="form-control">
                <option value="">Select Type</option>
                <option v-for="t in deviceTypes" :key="t.networkdevicetypeid" :value="t.networkdevicetypeid">
                  {{ t.networkdevicetype }}
                </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">
                <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">
              <!--
                The catalog model is where the device photo comes from: the
                detail page's hero image reads the model's imageurl, exactly as
                machines, PCs and printers do.
              -->
              <label for="modelnumberid">Model</label>
              <select id="modelnumberid" v-model="form.modelnumberid" class="form-control">
                <option value="">Select Model</option>
                <option v-for="m in filteredModels" :key="m.modelnumberid" :value="m.modelnumberid">
                  {{ m.modelnumber }}
                </option>
              </select>
            </div>
          </div>

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

          <div class="form-row">
            <div class="form-group">
              <label for="portcount">Port Count</label>
              <input
                id="portcount"
                v-model.number="form.portcount"
                type="number"
                class="form-control"
                min="0"
              />
            </div>
            <div class="form-group">
              <label for="rackunit">Rack Unit</label>
              <input
                id="rackunit"
                v-model="form.rackunit"
                type="text"
                class="form-control"
                placeholder="e.g., U1, U5-U8"
              />
            </div>
          </div>

          <div class="form-row checkboxes">
            <div class="form-group checkbox-group">
              <label>
                <input type="checkbox" v-model="form.ispoe" />
                <span>PoE Capable</span>
              </label>
              <small>Device supports Power over Ethernet</small>
            </div>
            <div class="form-group checkbox-group">
              <label>
                <input type="checkbox" v-model="form.ismanaged" />
                <span>Managed Device</span>
              </label>
              <small>Device has SNMP, web interface, or CLI management</small>
            </div>
          </div>
        </fieldset>

        <!-- Map Position (optional) -->
        <fieldset>
          <legend>Map Position (Optional)</legend>
          <!--
            Picked on the floor plan, the same way machines, PCs and printers do
            it. This form used to ask for the X and Y as raw numbers, which meant
            reading coordinates off another screen and typing them in.
          -->
          <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>
        </fieldset>

        <!-- 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>

        <!-- Notes -->
        <fieldset>
          <legend>Notes</legend>
          <div class="form-group">
            <textarea
              id="notes"
              v-model="form.notes"
              class="form-control"
              rows="4"
              placeholder="Additional notes about this device..."
            ></textarea>
          </div>
        </fieldset>

        <!-- Site-defined custom fields for network devices.
             NOT wrapped in a fieldset: the component renders nothing when a site
             has defined no custom fields, but a fieldset draws its border either
             way, so an empty box appeared after Notes. Every other asset form
             places this bare; this one was the exception. -->
        <CustomFieldsInputs ref="customFieldsRef" :assettypeid="NETWORK_ASSETTYPEID" :assetid="currentAssetId" />

        <!-- Form Actions -->
        <div class="form-actions">
          <button type="button" class="btn btn-secondary" @click="cancel">Cancel</button>
          <button type="submit" class="btn btn-primary" :disabled="saving">
            {{ saving ? 'Saving...' : (isEdit ? 'Save Changes' : 'Create Device') }}
          </button>
        </div>

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

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

const { isEnabled } = useIdentifierFlags()

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 route = useRoute()
const router = useRouter()

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

// Seeded asset-type id for network devices (see /api/assets/types).
const NETWORK_ASSETTYPEID = 3
const customFieldsRef = ref(null)
const currentAssetId = ref(null)

const form = ref({
  assetnumber: '',
  name: '',
  serialnumber: '',
  gaugelabreference: '',
  maintenancereference: '',
  statusid: '',
  locationid: '',
  businessunitid: '',
  hostname: '',
  ipaddress: '',
  networkdevicetypeid: '',
  vendorid: '',
  modelnumberid: '',
  firmwareversion: '',
  portcount: null,
  rackunit: '',
  ispoe: false,
  ismanaged: false,
  mapx: null,
  mapy: null,
  levelid: null,
  notes: ''
})

const deviceTypes = ref([])

// Preview of what the backend will generate. Mirrors
// plugins/network/services/assetnumbers.py - the server is authoritative and
// re-derives it; this only shows the operator what they are about to get.
const generatedAssetNumber = computed(() => {
  const cleaned = (value) => (value || '')
    .trim()
    .replace(/[\s_/\\]+/g, '-')
    .replace(/[^A-Za-z0-9.-]/g, '')
    .replace(/-{2,}/g, '-')
    .replace(/^-+|-+$/g, '')
  const name = cleaned(form.value.name)
  if (!name) return ''
  const found = deviceTypes.value.find(
    t => String(t.networkdevicetypeid) === String(form.value.networkdevicetypeid))
  const prefix = cleaned(found?.prefix).toUpperCase()
  if (!prefix) return name
  // never stack a prefix the name already carries (IDF-03 under type IDF)
  if (name.toUpperCase().startsWith(prefix + '-')) return name
  return `${prefix}-${name}`
})
// True when the record loaded WITHOUT an asset number, which unlocks the field
// so it can be repaired. Captured at load: once typed, the field must stay open.
const assetNumberMissing = ref(false)

const vendors = ref([])
const models = ref([])

// Models belong to a vendor, so picking one narrows the list - the same
// behaviour PCForm, MachineForm and PrinterForm have. With no vendor chosen the
// whole catalogue shows, rather than an empty dropdown that reads as "no models
// exist" when it means "pick a vendor first".
const filteredModels = computed(() => {
  if (!form.value.vendorid) return models.value
  return models.value.filter(m => m.vendorid === form.value.vendorid)
})
const locations = ref([])
const statuses = ref([])
const businessUnits = ref([])
const saving = ref(false)
const error = ref('')

onMounted(async () => {
  await Promise.all([
    loadDeviceTypes(),
    loadVendors(),
    loadLocations(),
    loadStatuses(),
    loadBusinessUnits()
  ])

  if (isEdit.value) {
    await loadDevice()
  }
})

async function loadDeviceTypes() {
  try {
    const response = await networkApi.types.list({ perpage: 100 })
    deviceTypes.value = response.data.data || []
  } catch (err) {
    console.error('Error loading device types:', err)
  }
}

async function loadVendors() {
  try {
    const response = await vendorsApi.list({ perpage: 100 })
    vendors.value = response.data.data || []
    // listAll: the models catalogue is already past the backend's 100-row
    // cap, so list() left the tail of it unselectable.
    models.value = await modelsApi.listAll()
  } catch (err) {
    console.error('Error loading vendors:', err)
  }
}

async function loadLocations() {
  try {
    const response = await locationsApi.list({ perpage: 100 })
    locations.value = response.data.data || []
  } catch (err) {
    console.error('Error loading locations:', err)
  }
}

async function loadStatuses() {
  try {
    const response = await assetsApi.statuses.list()
    statuses.value = response.data.data || []
  } catch (err) {
    console.error('Error loading statuses:', err)
  }
}

async function loadBusinessUnits() {
  try {
    const response = await businessunitsApi.list({ perpage: 100 })
    businessUnits.value = response.data.data || []
  } catch (err) {
    console.error('Error loading business units:', err)
  }
}

async function loadDevice() {
  try {
    const response = await networkApi.get(deviceId)
    const data = response.data.data
    currentAssetId.value = data.assetid || null

    // Populate form with existing data
    form.value.assetnumber = data.assetnumber || ''
    // Remember that it arrived empty, so the field stays editable while the
    // user types the number this record should have had.
    assetNumberMissing.value = !(data.assetnumber || '').trim()
    form.value.name = data.name || ''
    form.value.serialnumber = data.serialnumber || ''
    form.value.gaugelabreference = data.gaugelabreference || ''
    form.value.maintenancereference = data.maintenancereference || ''
    form.value.statusid = data.statusid || ''
    form.value.locationid = data.locationid || ''
    form.value.businessunitid = data.businessunitid || ''
    form.value.mapx = data.mapx
    form.value.mapy = data.mapy
    form.value.levelid = data.levelid
    form.value.notes = data.notes || ''
    // The IP lives in a Communication row, not on the extension table; the API
    // flattens it onto the response as ipaddress.
    form.value.ipaddress = data.ipaddress || ''

    // Network device specific
    if (data.networkdevice) {
      form.value.hostname = data.networkdevice.hostname || ''
      form.value.networkdevicetypeid = data.networkdevice.networkdevicetypeid || ''
      form.value.vendorid = data.networkdevice.vendorid || ''
      form.value.modelnumberid = data.networkdevice.modelnumberid || ''
      form.value.firmwareversion = data.networkdevice.firmwareversion || ''
      form.value.portcount = data.networkdevice.portcount
      form.value.rackunit = data.networkdevice.rackunit || ''
      form.value.ispoe = data.networkdevice.ispoe || false
      form.value.ismanaged = data.networkdevice.ismanaged || false
    }
  } catch (err) {
    console.error('Error loading device:', err)
    error.value = 'Failed to load device'
  }
}

async function submitForm() {
  saving.value = true
  error.value = ''

  try {
    const payload = {
      assetnumber: form.value.assetnumber,
      name: form.value.name || null,
      serialnumber: form.value.serialnumber || null,
      gaugelabreference: form.value.gaugelabreference || null,
      maintenancereference: form.value.maintenancereference || null,
      statusid: form.value.statusid || null,
      locationid: form.value.locationid || null,
      businessunitid: form.value.businessunitid || null,
      hostname: form.value.hostname || null,
      ipaddress: form.value.ipaddress || null,
      networkdevicetypeid: form.value.networkdevicetypeid || null,
      vendorid: form.value.vendorid || null,
      modelnumberid: form.value.modelnumberid || null,
      firmwareversion: form.value.firmwareversion || null,
      portcount: form.value.portcount || null,
      rackunit: form.value.rackunit || null,
      ispoe: form.value.ispoe,
      ismanaged: form.value.ismanaged,
      mapx: form.value.mapx,
      mapy: form.value.mapy,
      levelid: form.value.levelid,
      notes: form.value.notes || null
    }

    let assetId = currentAssetId.value
    let redirectId = deviceId
    if (isEdit.value) {
      const response = await networkApi.update(deviceId, payload)
      assetId = assetId || response.data?.data?.assetid
    } else {
      const response = await networkApi.create(payload)
      assetId = response.data.data?.assetid
      redirectId = response.data.data?.networkdevice?.networkdeviceid
    }

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

    router.push(redirectId ? `/network/${redirectId}` : '/network')
  } catch (err) {
    console.error('Error saving device:', err)
    error.value = apiError(err, 'Failed to save device')
  } finally {
    saving.value = false
  }
}

function cancel() {
  if (isEdit.value) {
    router.push(`/network/${deviceId}`)
  } else {
    router.push('/network')
  }
}
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
}

</script>

<style scoped>
.form-card {
  max-width: 800px;
}

fieldset {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 1.5rem;
  margin-bottom: 1.5rem;
}

legend {
  font-weight: 600;
  padding: 0 0.5rem;
  color: var(--text);
}

.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin-bottom: 1rem;
}

.form-row:last-child {
  margin-bottom: 0;
}

.form-group {
  display: flex;
  flex-direction: column;
}

.form-group label {
  margin-bottom: 0.375rem;
  font-weight: 500;
  color: var(--text);
}

.form-group small {
  margin-top: 0.25rem;
  color: var(--text-light);
  font-size: 0.8rem;
}

.checkboxes {
  margin-top: 1rem;
}

.checkbox-group label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
}

.checkbox-group input[type="checkbox"] {
  width: 1.125rem;
  height: 1.125rem;
}

.checkbox-group span {
  font-weight: 500;
}

.form-actions {
  display: flex;
  gap: 1rem;
  justify-content: flex-end;
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--border);
}

.error-message {
  margin-top: 1rem;
  padding: 0.75rem 1rem;
  background: var(--danger);
  color: white;
  border-radius: 6px;
}

@media (max-width: 600px) {
  .form-row {
    grid-template-columns: 1fr;
  }
}
</style>
