<template>
  <section class="content-grid">
    <v-card class="span-12 panel-pad">
      <div class="toolbar-row mb-3">
        <div>
          <h2 class="section-title">Parts inventory</h2>
          <div class="quiet text-body-2">Maintenance parts &amp; supplies — stock levels, aisle/bin locations, and reservations. Separate from the depreciation register.</div>
        </div>
        <v-spacer />
        <v-select
          v-model="categoryFilter"
          :items="categoryFilterItems"
          label="Category"
          density="compact"
          hide-details
          style="max-width:200px"
          @update:model-value="load"
        />
        <v-select
          v-model="statusFilter"
          :items="statusFilterItems"
          item-title="title"
          item-value="value"
          label="Status"
          density="compact"
          hide-details
          style="max-width:170px"
          @update:model-value="load"
        />
        <v-switch v-model="lowStockOnly" label="Low stock" color="warning" density="compact" hide-details inset @update:model-value="load" />
        <v-btn color="primary" prepend-icon="mdi-plus" @click="openNew">New part</v-btn>
      </div>

      <div class="kpi-row mb-3">
        <div class="kpi"><span class="kpi-value">{{ parts.length }}</span><span class="kpi-label">Parts</span></div>
        <div class="kpi"><span class="kpi-value">{{ totalOnHand }}</span><span class="kpi-label">Units on hand</span></div>
        <div class="kpi"><span class="kpi-value">{{ totalReserved }}</span><span class="kpi-label">Reserved</span></div>
        <div class="kpi"><span class="kpi-value">{{ currency(totalValue) }}</span><span class="kpi-label">Stock value</span></div>
        <div class="kpi"><span class="kpi-value text-warning">{{ lowStockCount }}</span><span class="kpi-label">Below reorder</span></div>
      </div>

      <DataTable
        :columns="columns"
        :rows="parts"
        row-key="id"
        :page-size="15"
        has-actions
        searchable
        search-placeholder="Filter parts"
        empty-text="No parts yet."
      >
        <template #cell-part_number="{ row }">
          <span class="font-weight-bold">{{ row.part_number }}</span>
          <v-chip v-if="row.low_stock" size="x-small" color="warning" variant="flat" class="ml-2">Low</v-chip>
          <v-chip v-if="row.status !== 'active'" size="x-small" variant="tonal" class="ml-2">{{ row.status }}</v-chip>
        </template>
        <template #cell-available="{ row }">
          <span :class="{ 'text-warning font-weight-bold': row.low_stock }">{{ row.available }}</span>
        </template>
        <template #actions="{ row }">
          <v-btn icon="mdi-pencil" size="small" variant="text" @click="openEdit(row)" />
          <v-btn v-if="canDelete" icon="mdi-delete-outline" size="small" variant="text" color="error" @click="remove(row)" />
        </template>
      </DataTable>
      <v-alert v-if="error" type="error" density="compact" class="mt-3">{{ error }}</v-alert>
    </v-card>

    <v-dialog v-model="dialog" max-width="920" scrollable>
      <v-card>
        <v-card-title>{{ form.id ? `Edit part · ${form.part_number}` : 'New part' }}</v-card-title>
        <v-card-text>
          <div class="form-grid">
            <v-text-field v-model="form.part_number" label="Part number *" />
            <v-text-field v-model="form.name" label="Name *" />
            <v-combobox v-model="form.category" :items="categoryOptions" label="Category" />
            <v-select v-model="form.status" :items="partStatusItems" item-title="title" item-value="value" label="Status" />
            <v-combobox v-model="form.unit_of_measure" :items="unitOfMeasureItems" label="Unit of measure" />
            <v-text-field v-model.number="form.unit_cost" type="number" label="Unit cost" prefix="$" />
            <v-text-field v-model.number="form.reorder_point" type="number" label="Reorder point" hint="Flag low stock at/below this" persistent-hint />
            <v-text-field v-model.number="form.reorder_quantity" type="number" label="Reorder quantity" />
            <v-text-field v-model="form.manufacturer" label="Manufacturer" />
            <v-text-field v-model="form.manufacturer_part_number" label="Manufacturer part #" />
            <v-text-field v-model="form.barcode" label="Barcode / UPC" />
            <v-autocomplete
              v-model="form.supplier_contact_id"
              :items="supplierItems"
              item-title="title"
              item-value="value"
              label="Supplier (from contacts)"
              clearable
            />
          </div>

          <v-textarea v-model="form.measurements" class="mt-3" label="Measurements / specifications" rows="2" placeholder="e.g. 12mm x 50mm, M8 thread, 24V" />
          <v-textarea v-model="form.description" class="mt-2" label="Description / identification notes" rows="2" />
          <v-textarea v-model="form.notes" class="mt-2" label="Internal notes" rows="2" />

          <template v-if="form.id">
            <!-- ---- Stock locations ---- -->
            <v-divider class="my-4" />
            <div class="toolbar-row mb-2">
              <h3 class="section-title">Stock locations</h3>
              <v-spacer />
              <v-chip size="small" variant="tonal">On hand {{ form.on_hand }} · Reserved {{ form.reserved }} · Available {{ form.available }}</v-chip>
            </div>
            <v-table density="compact" class="mb-3">
              <thead>
                <tr>
                  <th>Location</th><th>Aisle</th><th>Bin</th>
                  <th class="text-right">On hand</th><th class="text-right">Reserved</th><th class="text-right">Available</th><th />
                </tr>
              </thead>
              <tbody>
                <tr v-for="s in form.stock" :key="s.id">
                  <td>{{ s.location_name }}</td>
                  <td>{{ s.aisle }}</td>
                  <td>{{ s.bin }}</td>
                  <td class="text-right">{{ s.quantity }}</td>
                  <td class="text-right">{{ s.reserved }}</td>
                  <td class="text-right">{{ s.available }}</td>
                  <td class="text-right">
                    <v-btn icon="mdi-pencil" size="x-small" variant="text" @click="editStock(s)" />
                    <v-btn icon="mdi-delete-outline" size="x-small" variant="text" color="error" @click="removeStock(s)" />
                  </td>
                </tr>
                <tr v-if="!form.stock.length"><td colspan="7" class="quiet">No stock locations yet.</td></tr>
              </tbody>
            </v-table>
            <div class="form-grid">
              <v-select v-model="stockDraft.location_contact_id" :items="locationItems" item-title="title" item-value="value" label="Work location" clearable />
              <v-text-field v-model="stockDraft.aisle" label="Aisle" />
              <v-text-field v-model="stockDraft.bin" label="Bin" />
              <v-text-field v-model.number="stockDraft.quantity" type="number" label="On hand" />
              <v-text-field v-model.number="stockDraft.reserved" type="number" label="Reserved" />
              <div class="d-flex align-center">
                <v-btn variant="tonal" prepend-icon="mdi-content-save" @click="saveStock">{{ stockDraft.id ? 'Update location' : 'Add location' }}</v-btn>
                <v-btn v-if="stockDraft.id" variant="text" class="ml-1" @click="resetStockDraft">Cancel</v-btn>
              </div>
            </div>

            <!-- ---- Stock movements ---- -->
            <v-divider class="my-4" />
            <h3 class="section-title mb-2">Record movement</h3>
            <div class="form-grid">
              <v-select v-model="txDraft.stock_id" :items="stockLocationItems" item-title="title" item-value="value" label="Stock location" />
              <v-select v-model="txDraft.type" :items="partTransactionTypes" item-title="title" item-value="value" label="Movement" />
              <v-text-field v-model.number="txDraft.quantity" type="number" :label="txDraft.type === 'adjust' ? 'New on-hand count' : 'Quantity'" />
              <v-autocomplete v-model="txDraft.asset_id" :items="assetItems" item-title="title" item-value="value" label="Asset (optional)" clearable />
              <v-text-field v-model="txDraft.notes" class="full" label="Notes / reference" />
            </div>
            <div class="text-right mb-3">
              <v-btn color="primary" variant="tonal" prepend-icon="mdi-swap-vertical" :disabled="!txDraft.stock_id" @click="recordTransaction">Apply movement</v-btn>
            </div>
            <v-table v-if="form.transactions && form.transactions.length" density="compact" class="movement-log">
              <thead>
                <tr><th>When</th><th>Movement</th><th class="text-right">Qty</th><th>Location</th><th>Asset</th><th>By</th><th>Notes</th></tr>
              </thead>
              <tbody>
                <tr v-for="t in form.transactions" :key="t.id">
                  <td>{{ shortDate(t.created_at) }}</td>
                  <td>{{ txLabel(t.type) }}</td>
                  <td class="text-right">{{ t.quantity }}</td>
                  <td>{{ t.location_name }}<span v-if="t.aisle"> · {{ t.aisle }}/{{ t.bin }}</span></td>
                  <td>{{ t.asset_code }}</td>
                  <td>{{ t.created_by_name }}</td>
                  <td style="white-space:normal">{{ t.notes }}</td>
                </tr>
              </tbody>
            </v-table>

            <!-- ---- Photos ---- -->
            <v-divider class="my-4" />
            <div class="toolbar-row mb-2">
              <h3 class="section-title">Photos</h3>
              <v-spacer />
              <v-btn variant="tonal" prepend-icon="mdi-camera-plus-outline" @click="$refs.photoInput.click()">Add photo</v-btn>
              <input ref="photoInput" type="file" accept="image/*" hidden @change="onPhoto" />
            </div>
            <div v-if="form.photos && form.photos.length" class="photo-grid">
              <div v-for="p in form.photos" :key="p.id" class="photo-tile">
                <img :src="p.data" :alt="p.name || 'part photo'" />
                <v-btn icon="mdi-close" size="x-small" color="error" variant="flat" class="photo-remove" @click="removePhoto(p.id)" />
              </div>
            </div>
            <div v-else class="quiet text-body-2">No photos yet.</div>
          </template>

          <v-alert v-if="dialogError" type="error" density="compact" class="mt-3">{{ dialogError }}</v-alert>
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn variant="text" @click="dialog = false">Close</v-btn>
          <v-btn color="primary" prepend-icon="mdi-content-save" :loading="saving" @click="save">{{ form.id ? 'Save changes' : 'Create part' }}</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </section>
</template>

<script>
import DataTable from '../components/DataTable.vue';
import { apiRequest } from '../services/api';
import { currency, shortDate } from '../utils/format';
import { clonePlain } from '../utils/clone';
import { partStatusItems, partTransactionTypes, unitOfMeasureItems } from '../constants';

function blankPart() {
  return {
    id: null, part_number: '', name: '', description: '', category: '', manufacturer: '',
    manufacturer_part_number: '', barcode: '', unit_of_measure: 'each', unit_cost: 0,
    reorder_point: 0, reorder_quantity: 0, measurements: '', supplier_contact_id: null,
    status: 'active', notes: '',
    on_hand: 0, reserved: 0, available: 0, stock: [], photos: [], transactions: []
  };
}

function blankStockDraft() {
  return { id: null, location_contact_id: null, aisle: '', bin: '', quantity: 0, reserved: 0 };
}

function blankTxDraft() {
  return { stock_id: null, type: 'receive', quantity: 1, asset_id: null, notes: '' };
}

export default {
  components: { DataTable },
  props: {
    token: { type: String, required: true },
    canDelete: { type: Boolean, default: false }
  },
  data() {
    return {
      partStatusItems,
      partTransactionTypes,
      unitOfMeasureItems,
      parts: [],
      contacts: [],
      assets: [],
      managedCategories: [],
      categoryFilter: null,
      statusFilter: null,
      lowStockOnly: false,
      dialog: false,
      form: blankPart(),
      stockDraft: blankStockDraft(),
      txDraft: blankTxDraft(),
      saving: false,
      error: '',
      dialogError: '',
      columns: [
        { key: 'part_number', label: 'Part #' },
        { key: 'name', label: 'Name' },
        { key: 'category', label: 'Category' },
        { key: 'supplier_name', label: 'Supplier' },
        { key: 'on_hand', label: 'On hand', format: 'number' },
        { key: 'reserved', label: 'Reserved', format: 'number' },
        { key: 'available', label: 'Available', format: 'number' },
        { key: 'location_count', label: 'Locations', format: 'number' }
      ]
    };
  },
  computed: {
    categoryOptions() {
      // Admin-managed parts categories, plus any value already in use so existing parts stay selectable.
      const inUse = this.parts.map((p) => p.category).filter(Boolean);
      return [...new Set([...this.managedCategories, ...inUse])].sort((a, b) => String(a).localeCompare(String(b)));
    },
    categoryFilterItems() {
      return ['All categories', ...this.categoryOptions].map((c) => (c === 'All categories' ? { title: c, value: null } : c));
    },
    statusFilterItems() {
      return [{ title: 'All statuses', value: null }, ...partStatusItems];
    },
    supplierItems() {
      return this.contacts
        .filter((c) => ['vendor', 'service_provider', 'contractor'].includes(c.type))
        .map((c) => ({ title: c.display_name, value: c.id }));
    },
    locationItems() {
      return this.contacts
        .filter((c) => c.type === 'work_location')
        .map((c) => ({ title: c.display_name, value: c.id }));
    },
    assetItems() {
      return this.assets.map((a) => ({ title: `${a.asset_id} · ${a.description}`, value: a.id }));
    },
    stockLocationItems() {
      return (this.form.stock || []).map((s) => ({
        title: `${s.location_name}${s.aisle ? ` · ${s.aisle}/${s.bin || '—'}` : ''} (on hand ${s.quantity})`,
        value: s.id
      }));
    },
    totalOnHand() {
      return this.parts.reduce((sum, p) => sum + Number(p.on_hand || 0), 0);
    },
    totalReserved() {
      return this.parts.reduce((sum, p) => sum + Number(p.reserved || 0), 0);
    },
    totalValue() {
      return this.parts.reduce((sum, p) => sum + Number(p.stock_value || 0), 0);
    },
    lowStockCount() {
      return this.parts.filter((p) => p.low_stock).length;
    }
  },
  mounted() {
    this.load();
    this.loadContacts();
    this.loadAssets();
    this.loadCategories();
  },
  methods: {
    currency,
    shortDate,
    async api(path, options = {}) {
      return apiRequest(path, this.token, options);
    },
    txLabel(type) {
      return (partTransactionTypes.find((t) => t.value === type) || {}).title || type;
    },
    async load() {
      this.error = '';
      try {
        const params = new URLSearchParams();
        if (this.categoryFilter) params.set('category', this.categoryFilter);
        if (this.statusFilter) params.set('status', this.statusFilter);
        if (this.lowStockOnly) params.set('low_stock', 'true');
        const data = await (await this.api(`/api/parts?${params.toString()}`)).json();
        this.parts = data.parts;
      } catch (error) {
        this.error = error.message;
      }
    },
    async loadContacts() {
      try {
        const data = await (await this.api('/api/contacts')).json();
        this.contacts = data.contacts;
      } catch {
        this.contacts = [];
      }
    },
    async loadAssets() {
      try {
        const data = await (await this.api('/api/assets')).json();
        this.assets = data.assets;
      } catch {
        this.assets = [];
      }
    },
    async loadCategories() {
      try {
        const data = await (await this.api('/api/part-categories')).json();
        this.managedCategories = (data.categories || []).map((category) => category.name).filter(Boolean);
      } catch {
        this.managedCategories = [];
      }
    },
    openNew() {
      this.form = blankPart();
      this.resetStockDraft();
      this.txDraft = blankTxDraft();
      this.dialogError = '';
      this.dialog = true;
    },
    async openEdit(part) {
      this.dialogError = '';
      this.resetStockDraft();
      this.txDraft = blankTxDraft();
      const data = await (await this.api(`/api/parts/${part.id}`)).json();
      this.form = { ...blankPart(), ...clonePlain(data.part) };
      this.dialog = true;
    },
    setForm(part) {
      this.form = { ...blankPart(), ...clonePlain(part) };
    },
    async save() {
      this.saving = true;
      this.dialogError = '';
      try {
        const method = this.form.id ? 'PUT' : 'POST';
        const url = this.form.id ? `/api/parts/${this.form.id}` : '/api/parts';
        const data = await (await this.api(url, { method, body: JSON.stringify(this.form) })).json();
        this.setForm(data.part);
        await this.load();
      } catch (error) {
        this.dialogError = error.message;
      } finally {
        this.saving = false;
      }
    },
    async remove(part) {
      if (!window.confirm(`Delete part ${part.part_number}?`)) return;
      try {
        await this.api(`/api/parts/${part.id}`, { method: 'DELETE' });
        await this.load();
      } catch (error) {
        this.error = error.message;
      }
    },
    resetStockDraft() {
      this.stockDraft = blankStockDraft();
    },
    editStock(s) {
      this.stockDraft = { id: s.id, location_contact_id: s.location_contact_id, aisle: s.aisle, bin: s.bin, quantity: s.quantity, reserved: s.reserved };
    },
    async saveStock() {
      this.dialogError = '';
      try {
        const data = await (await this.api(`/api/parts/${this.form.id}/stock`, { method: 'POST', body: JSON.stringify(this.stockDraft) })).json();
        this.setForm(data.part);
        this.resetStockDraft();
        await this.load();
      } catch (error) {
        this.dialogError = error.message;
      }
    },
    async removeStock(s) {
      if (!window.confirm('Remove this stock location?')) return;
      const data = await (await this.api(`/api/parts/${this.form.id}/stock/${s.id}`, { method: 'DELETE' })).json();
      this.setForm(data.part);
      await this.load();
    },
    async recordTransaction() {
      this.dialogError = '';
      try {
        const data = await (await this.api(`/api/parts/${this.form.id}/transactions`, { method: 'POST', body: JSON.stringify(this.txDraft) })).json();
        this.setForm(data.part);
        this.txDraft = blankTxDraft();
        await this.load();
      } catch (error) {
        this.dialogError = error.message;
      }
    },
    onPhoto(event) {
      const [file] = event.target.files || [];
      if (!file) return;
      const reader = new FileReader();
      reader.onload = async () => {
        try {
          const data = await (await this.api(`/api/parts/${this.form.id}/photos`, {
            method: 'POST',
            body: JSON.stringify({ name: file.name, mime: file.type, data: reader.result })
          })).json();
          this.setForm(data.part);
        } catch (error) {
          this.dialogError = error.message;
        }
      };
      reader.readAsDataURL(file);
      event.target.value = '';
    },
    async removePhoto(id) {
      const data = await (await this.api(`/api/parts/${this.form.id}/photos/${id}`, { method: 'DELETE' })).json();
      this.setForm(data.part);
    }
  }
};
</script>

<style scoped>
.kpi-row {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}
.kpi {
  display: flex;
  flex-direction: column;
  padding: 10px 16px;
  border-radius: 10px;
  background: rgba(127, 127, 127, 0.08);
  min-width: 120px;
}
.kpi-value {
  font-size: 1.25rem;
  font-weight: 700;
}
.kpi-label {
  font-size: 0.75rem;
  opacity: 0.7;
}
.photo-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.photo-tile {
  position: relative;
  width: 110px;
  height: 110px;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid rgba(127, 127, 127, 0.25);
}
.photo-tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.photo-remove {
  position: absolute;
  top: 4px;
  right: 4px;
}
.movement-log {
  max-height: 240px;
  overflow-y: auto;
}
</style>
