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

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

      <!-- The record failed to load. Show the reason INSTEAD of the form: an
           empty edit form is indistinguishable from a record whose fields are
           genuinely empty, and saving it would write the blanks back. -->
      <div v-else-if="loadFailed" class="error-message">{{ error }}</div>

      <form v-else @submit.prevent="saveMachine">
        <!-- Identity Section -->
        <h3 class="form-section-title">Identity</h3>
        <div class="form-row">
          <div class="form-group">
            <label for="assetnumber">Asset Number *</label>
            <input
              id="assetnumber"
              v-model="form.assetnumber"
              type="text"
              class="form-control"
              required
            />
          </div>

          <div class="form-group">
            <label for="name">Name / Alias</label>
            <input
              id="name"
              v-model="form.name"
              type="text"
              class="form-control"
            />
            <small class="form-help">Layperson-friendly label</small>
          </div>
        </div>

        <div class="form-row" v-if="isEnabled('gaugelabreference', 'machine') || isEnabled('maintenancereference', 'machine')">
          <div class="form-group" v-if="isEnabled('gaugelabreference', 'machine')">
            <label for="gaugelabreference">Gauge Lab Reference</label>
            <input
              id="gaugelabreference"
              v-model="form.gaugelabreference"
              type="text"
              class="form-control"
            />
            <small class="form-help">Authoritative gauge lab asset reference (if tracked)</small>
          </div>

          <div class="form-group" v-if="isEnabled('maintenancereference', 'machine')">
            <label for="maintenancereference">Maintenance Reference</label>
            <input
              id="maintenancereference"
              v-model="form.maintenancereference"
              type="text"
              class="form-control"
            />
            <small class="form-help">Maintenance system asset reference (if tracked)</small>
          </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>

        <!-- Machine Hardware Section -->
        <h3 class="form-section-title">Machine Hardware</h3>
        <div class="form-row">
          <div class="form-group">
            <label for="machinetypeid">Machine Type</label>
            <select
              id="machinetypeid"
              v-model="form.machinetypeid"
              class="form-control"
            >
              <option value="">Select type...</option>
              <option
                v-for="mt in machineTypes"
                :key="mt.machinetypeid"
                :value="mt.machinetypeid"
              >
                {{ mt.machinetype }}
              </option>
            </select>
          </div>

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

        <div class="form-row">
          <div class="form-group">
            <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>
            <small class="form-help" v-if="form.vendorid">Filtered by selected vendor</small>
          </div>

          <div class="form-group"></div>
        </div>

        <!-- Controller Section (for CNC machines) -->
        <h3 class="form-section-title">Controller</h3>
        <div class="form-row">
          <div class="form-group">
            <label for="controllervendorid">Controller Vendor</label>
            <select
              id="controllervendorid"
              v-model="form.controllervendorid"
              class="form-control"
            >
              <option value="">Select vendor...</option>
              <option
                v-for="v in vendors"
                :key="v.vendorid"
                :value="v.vendorid"
              >
                {{ v.vendor }}
              </option>
            </select>
            <small class="form-help">e.g., Fanuc, Siemens, Allen-Bradley</small>
          </div>

          <div class="form-group">
            <label for="controllermodelid">Controller Model</label>
            <select
              id="controllermodelid"
              v-model="form.controllermodelid"
              class="form-control"
            >
              <option value="">Select model...</option>
              <option
                v-for="m in filteredControllerModels"
                :key="m.modelnumberid"
                :value="m.modelnumberid"
              >
                {{ m.modelnumber }}
              </option>
            </select>
            <small class="form-help" v-if="form.controllervendorid">Filtered by controller vendor</small>
          </div>
        </div>

        <!-- Location Section -->
        <h3 class="form-section-title">Location & Organization</h3>
        <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="l in locations"
                :key="l.locationid"
                :value="l.locationid"
              >
                {{ l.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>

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

        <!-- Configuration Section -->
        <h3 class="form-section-title">Configuration</h3>
        <div class="form-row">
          <div class="form-group checkbox-group">
            <label>
              <input type="checkbox" v-model="form.requiresmanualconfig" />
              Requires Manual Config
            </label>
            <small class="form-help">Machine a tech must configure by hand (e.g. driven by multiple PCs)</small>
          </div>
        </div>

        <!-- Controlling PC Selection -->
        <h3 class="form-section-title">Connected PC</h3>
        <div class="form-row">
          <div class="form-group">
            <label for="controllingpc">Controlling PC</label>
            <select
              id="controllingpc"
              v-model="controllingPcId"
              class="form-control"
            >
              <option :value="null">None (standalone)</option>
              <option
                v-for="pc in pcs"
                :key="pc.assetid"
                :value="pc.assetid"
              >
                {{ pc.assetnumber }}{{ pc.name ? ` (${pc.name})` : '' }}
              </option>
            </select>
            <small class="form-help">Select the PC that controls this machine</small>
          </div>

          <div class="form-group" v-if="controllingPcId">
            <label for="connectiontype">Connection Type</label>
            <select
              id="connectiontype"
              v-model="relationshipTypeId"
              class="form-control"
            >
              <option
                v-for="rt in relationshipTypes"
                :key="rt.relationshiptypeid"
                :value="rt.relationshiptypeid"
              >
                {{ rt.relationshiptype }}
              </option>
            </select>
            <small class="form-help">How the PC connects to this machine</small>
          </div>
        </div>

        <!-- Notes Section -->
        <h3 class="form-section-title">Notes</h3>
        <div class="form-group">
          <textarea
            id="notes"
            v-model="form.notes"
            class="form-control"
            rows="3"
            placeholder="Additional notes..."
          ></textarea>
        </div>

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

        <!-- Printers belong to the MACHINE, so whichever PC controls it installs
             them - including a replacement after a reimage. -->
        <PrinterAssignmentPicker ref="printerPickerRef" :assetid="currentAssetId" scope="machine" />

        <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 Machine' }}
          </button>
          <router-link to="/machines" 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 { machinesApi, vendorsApi, locationsApi, modelsApi, businessunitsApi, computersApi, assetsApi, relationshipTypesApi } 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 PrinterAssignmentPicker from '@/components/PrinterAssignmentPicker.vue'
import { currentTheme } from '@/stores/theme'
import { useIdentifierFlags } from '@/composables/identifierSettings'
import { apiError } from '@/utils/apiError'

const { isEnabled } = useIdentifierFlags()

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

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

// Seeded asset-type id for machines (see /api/assets/types).
const MACHINE_ASSETTYPEID = 1
const customFieldsRef = ref(null)
const printerPickerRef = ref(null)
const currentAssetId = ref(null)

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({
  assetnumber: '',
  name: '',
  gaugelabreference: '',
  maintenancereference: '',
  serialnumber: '',
  statusid: 1,
  machinetypeid: '',
  vendorid: '',
  modelnumberid: '',
  controllervendorid: '',
  controllermodelid: '',
  locationid: '',
  businessunitid: '',
  requiresmanualconfig: false,
  islocationonly: false,
  notes: '',
  mapx: null,
  mapy: null,
  levelid: null
})

const machineTypes = ref([])
const statuses = ref([])
const vendors = ref([])
const locations = ref([])
const models = ref([])
// Set when the record itself could not be loaded, as opposed to a reference
// list failing. The form is withheld entirely, because an empty edit form is
// indistinguishable from a record whose fields are genuinely empty.
const loadFailed = ref(false)
const businessunits = ref([])
const pcs = ref([])
const relationshipTypes = ref([])
const controllingPcId = ref(null)
const relationshipTypeId = ref(null)
const existingRelationshipId = ref(null)
const currentMachine = ref(null)

// Filter models by selected machine vendor
const filteredModels = computed(() => {
  if (!form.value.vendorid) return models.value
  return models.value.filter(m => m.vendorid === form.value.vendorid)
})

// Filter models by selected controller vendor
const filteredControllerModels = computed(() => {
  if (!form.value.controllervendorid) return models.value
  return models.value.filter(m => m.vendorid === form.value.controllervendorid)
})

// Clear model selection when vendor changes
watch(() => form.value.vendorid, (newVal, oldVal) => {
  if (oldVal && newVal !== oldVal) {
    const currentModel = models.value.find(m => m.modelnumberid === form.value.modelnumberid)
    if (currentModel && currentModel.vendorid !== newVal) {
      form.value.modelnumberid = ''
    }
  }
})

// Clear controller model when controller vendor changes
watch(() => form.value.controllervendorid, (newVal, oldVal) => {
  if (oldVal && newVal !== oldVal) {
    const currentModel = models.value.find(m => m.modelnumberid === form.value.controllermodelid)
    if (currentModel && currentModel.vendorid !== newVal) {
      form.value.controllermodelid = ''
    }
  }
})

onMounted(async () => {
  try {
    // Load reference data in parallel
    const [typesRes, statusRes, vendorRes, locRes, allModels, buRes, pcsRes, relTypesRes] = await Promise.all([
      machinesApi.types.list(),
      assetsApi.statuses.list(),
      vendorsApi.list({ perpage: 500 }),
      locationsApi.list({ perpage: 500 }),
      modelsApi.listAll(),  // backend caps perpage at 100; page through all
      businessunitsApi.list({ perpage: 500 }),
      computersApi.listAll(),  // backend caps perpage at 100; page through all
      assetsApi.types.list()  // Used for relationship types, will fix below
    ])

    machineTypes.value = typesRes.data.data || []
    statuses.value = statusRes.data.data || []
    vendors.value = vendorRes.data.data || []
    locations.value = locRes.data.data || []
    models.value = allModels
    businessunits.value = buRes.data.data || []
    // listAll resolves to the ARRAY, not a response: fetchAllPages already
    // unwrapped every page. Reading .data.data off it threw, and the whole
    // parallel load went to the catch - so every dropdown on this form came up
    // empty and the machine's own values never loaded.
    pcs.value = pcsRes || []

    // Load relationship types separately
    try {
      const relRes = await relationshipTypesApi.list()
      relationshipTypes.value = relRes.data.data || []
    } catch (e) {
      // Fallback - use hardcoded Controls type
      relationshipTypes.value = [{ relationshiptypeid: 1, relationshiptype: 'Controls' }]
    }

    // Set default relationship type to "Controls" if available (name is data, compare folded)
    const controlsType = relationshipTypes.value.find(t => (t.relationshiptype || '').toLowerCase() === 'controls')
    if (controlsType) {
      relationshipTypeId.value = controlsType.relationshiptypeid
    }

    // Load machine if editing.
    //
    // ITS OWN try/catch, deliberately. This used to sit inside the same block
    // as the eight reference loads above, so ONE transient failure among them -
    // a page of listAll() timing out on a busy collector cycle - rejected the
    // whole thing and rendered a fully editable EDIT form with every field
    // BLANK, including the required Asset Number, next to a Save button. Typing
    // a number and saving then wrote the blank-loaded values over a real
    // machine. The reference lists degrade to empty dropdowns; the record must
    // not degrade at all.
    if (isEdit.value) {
      let response
      try {
        response = await machinesApi.get(route.params.id)
      } catch (err) {
        console.error('Error loading machine:', err)
        error.value = 'Could not load this machine. Nothing has been changed - '
          + 'reload the page rather than saving, or the blank form would '
          + 'overwrite the record.'
        loadFailed.value = true
        loading.value = false
        return
      }
      const data = response.data.data
      currentAssetId.value = data.assetid || null
      currentMachine.value = data

      form.value = {
        assetnumber: data.assetnumber || '',
        name: data.name || '',
        gaugelabreference: data.gaugelabreference || '',
        maintenancereference: data.maintenancereference || '',
        serialnumber: data.serialnumber || '',
        statusid: data.statusid || 1,
        machinetypeid: data.machine?.machinetypeid || '',
        vendorid: data.machine?.vendorid || '',
        modelnumberid: data.machine?.modelnumberid || '',
        controllervendorid: data.machine?.controllervendorid || '',
        controllermodelid: data.machine?.controllermodelid || '',
        locationid: data.locationid || '',
        businessunitid: data.businessunitid || '',
        requiresmanualconfig: data.machine?.requiresmanualconfig || false,
        islocationonly: data.machine?.islocationonly || false,
        notes: data.notes || '',
        mapx: data.mapx ?? null,
        mapy: data.mapy ?? null,
        levelid: data.levelid ?? null,
      }

      // Load existing relationships to find controlling PC
      if (data.assetid) {
        try {
          const relResponse = await assetsApi.getRelationships(data.assetid)
          const relationships = relResponse.data.data || { incoming: [], outgoing: [] }

          // Check incoming relationships for a controlling PC
          for (const rel of relationships.incoming || []) {
            if (rel.sourceasset?.assettypename === 'computer' && (rel.relationshiptypename || '').toLowerCase() === 'controls') {
              controllingPcId.value = rel.sourceasset.assetid
              relationshipTypeId.value = rel.relationshiptypeid
              existingRelationshipId.value = rel.assetrelationshipid
              break
            }
          }
        } catch (e) {
        }
      }
    }
  } 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 saveMachine() {
  error.value = ''
  saving.value = true

  try {
    const data = {
      assetnumber: form.value.assetnumber,
      name: form.value.name || null,
      gaugelabreference: form.value.gaugelabreference || null,
      maintenancereference: form.value.maintenancereference || null,
      serialnumber: form.value.serialnumber || null,
      statusid: form.value.statusid || 1,
      machinetypeid: form.value.machinetypeid || null,
      vendorid: form.value.vendorid || null,
      modelnumberid: form.value.modelnumberid || null,
      controllervendorid: form.value.controllervendorid || null,
      controllermodelid: form.value.controllermodelid || null,
      locationid: form.value.locationid || null,
      businessunitid: form.value.businessunitid || null,
      requiresmanualconfig: form.value.requiresmanualconfig,
      islocationonly: form.value.islocationonly,
      notes: form.value.notes || null,
      mapx: form.value.mapx,
      mapy: form.value.mapy
    }

    let savedMachine
    let assetId

    if (isEdit.value) {
      const response = await machinesApi.update(route.params.id, data)
      savedMachine = response.data.data
      assetId = savedMachine.assetid
    } else {
      const response = await machinesApi.create(data)
      savedMachine = response.data.data
      assetId = savedMachine.assetid
    }

    // Handle relationship (controlling PC)
    await saveRelationship(assetId)

    // Persist custom-field values against the asset id.
    if (assetId && customFieldsRef.value) {
      try {
        await customFieldsRef.value.save(assetId)
      } catch (cfErr) {
        console.error('Error saving custom fields:', cfErr)
      }
    }

    // Printer assignment, after the asset exists so a new machine can be
    // assigned in the same save. A failure here must not lose the machine the
    // user just entered, so it is reported and not thrown.
    if (assetId && printerPickerRef.value) {
      try {
        await printerPickerRef.value.save(assetId)
      } catch (printerErr) {
        console.error('Error saving printer assignment:', printerErr)
      }
    }

    router.push(`/machines/${savedMachine.machine?.machineid || route.params.id}`)
  } catch (err) {
    console.error('Error saving machine:', err)
    error.value = apiError(err, 'Failed to save machine')
  } finally {
    saving.value = false
  }
}

async function saveRelationship(assetId) {
  // If no PC selected and no existing relationship, nothing to do
  if (!controllingPcId.value && !existingRelationshipId.value) {
    return
  }

  // If clearing the relationship
  if (!controllingPcId.value && existingRelationshipId.value) {
    await assetsApi.deleteRelationship(existingRelationshipId.value)
    return
  }

  // If PC is selected
  if (controllingPcId.value) {
    // If there's an existing relationship, delete it first
    if (existingRelationshipId.value) {
      await assetsApi.deleteRelationship(existingRelationshipId.value)
    }

    // Create new relationship (PC controls Machine, so PC is source, Machine is target)
    await assetsApi.createRelationship({
      sourceassetid: controllingPcId.value,
      targetassetid: assetId,
      relationshiptypeid: relationshipTypeId.value
    })
  }
}
</script>

<style scoped>
.form-section-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text);
  margin: 1.5rem 0 0.75rem 0;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--border);
}

.form-section-title:first-of-type {
  margin-top: 0;
}

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

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

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

.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-radius: 4px;
  font-family: monospace;
}

.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-help {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.8rem;
  color: var(--text-light);
}
</style>
