<template>
  <section class="page-grid">
    <section class="panel panel-hero master-compact-hero">
      <div class="hero-copy">
        <p class="eyebrow">BOM管理</p>
        <span
          class="title-with-help"
          title="同一 BOM 编码可维护多个版本，已被引用的版本不直接改写，改版本号后会自动作为新版本保存。"
        >
          <h3>按编码维护多版本用料，并以默认版本驱动 MRP 与领料</h3>
        </span>
      </div>
    </section>

    <section class="panel">
        <div class="panel-header">
          <div>
            <p class="eyebrow">BOM列表</p>
            <h3>按编码聚合查看版本</h3>
          </div>
          <div class="workflow-inline-actions">
            <span class="panel-tag">正式主数据</span>
            <button class="primary-button" type="button" @click="openCreateDrawer">新增 BOM</button>
          </div>
        </div>

        <div v-if="feedbackMessage" class="feedback-banner">{{ feedbackMessage }}</div>
        <div v-if="errorMessage" class="feedback-banner error-banner">{{ errorMessage }}</div>

        <TableControls
          v-model:search="bomControls.search.value"
          v-model:sort-key="bomControls.sortKey.value"
          v-model:sort-direction="bomControls.sortDirection.value"
          :sort-options="bomControls.sortOptions"
          placeholder="搜索BOM编码、产品、版本、状态"
        />

        <div class="table-wrap">
          <table class="data-table compact-table">
            <thead>
              <tr>
                <th>BOM编码</th>
                <th>产品</th>
                <th>版本</th>
                <th>默认</th>
                <th>状态</th>
                <th>明细数</th>
                <th>操作</th>
              </tr>
            </thead>
            <tbody>
              <tr
                v-for="bom in paginatedBoms"
                :key="bom.bom_code"
                :class="{ 'row-selected': selectedBomId === Number(versionSelections[bom.bom_code] || bom.bom_id) }"
              >
                <td>
                  <button class="link-button" type="button" @click="openDetailDrawer(bom)">
                    {{ bom.bom_code }}
                  </button>
                </td>
                <td>{{ formatProductLabel(bom) }}</td>
                <td>
                  <select v-model.number="versionSelections[bom.bom_code]" @change="applyBomVersion(bom.bom_code)">
                    <option v-for="option in bom.version_options" :key="option.bom_id" :value="option.bom_id">
                      {{ option.version_no }}
                    </option>
                  </select>
                </td>
                <td>{{ bom.is_default ? "是" : "否" }}</td>
                <td>{{ formatStatusLabel(bom.status) }}</td>
                <td>{{ bom.item_count }}</td>
                <td class="action-row">
                  <button class="ghost-button" type="button" @click="startEdit(bom)">编辑</button>
                  <button class="ghost-button danger-ghost" type="button" @click="removeBom(bom)">删除</button>
                </td>
              </tr>
              <tr v-if="!filteredBoms.length">
                <td colspan="7" class="empty-row">暂无BOM主档</td>
              </tr>
            </tbody>
          </table>
        </div>
        <PaginationBar v-model:page="bomPage" v-model:page-size="bomPageSize" :total="filteredBoms.length" />
    </section>

    <FormDrawer
      :open="drawerOpen"
      eyebrow="BOM资料"
      :title="editingBomId ? '编辑BOM' : '新增BOM'"
      description="维护产品默认用料、版本、生效日期和明细重量口径。"
      :tag="editingBomId ? '编辑模式' : '新建模式'"
      wide
      @close="closeDrawer"
    >
      <form class="stack-form" @submit.prevent="submitBom">
        <div class="double-field">
          <label class="form-field">
            <span>BOM编码</span>
            <input :value="bomCodePreview" type="text" disabled readonly />
          </label>
          <label class="form-field">
            <span>产品 <i class="required-mark">*</i></span>
            <select v-model.number="form.product_item_id" required>
              <option disabled value="">请选择产品</option>
              <option v-for="product in products" :key="product.item_id" :value="product.item_id">
                {{ formatProductLabel(product) }}
              </option>
            </select>
          </label>
        </div>

        <div class="triple-field">
          <label class="form-field">
            <span>版本号 <i class="required-mark">*</i></span>
            <input v-model.trim="form.version_no" type="text" required />
          </label>
          <label class="form-field">
            <span>生效日期</span>
            <input v-model="form.effective_date" type="date" />
          </label>
          <label class="form-field">
            <span>状态</span>
            <select v-model="form.status">
              <option v-for="option in statusOptions" :key="option.value" :value="option.value">
                {{ option.label }}
              </option>
            </select>
          </label>
        </div>

        <div class="checkbox-grid">
          <label class="checkbox-field">
            <input v-model="form.is_default" type="checkbox" />
            <span>设为默认BOM</span>
          </label>
        </div>

        <label class="form-field">
          <span>备注</span>
          <textarea v-model.trim="form.remark" rows="2"></textarea>
        </label>

        <div class="subsection-head">
          <strong>BOM明细</strong>
          <button class="ghost-button" type="button" @click="addRow">增加一行</button>
        </div>

        <div class="order-item-stack">
          <article v-for="(item, index) in form.items" :key="index" class="order-item-card">
            <div class="subsection-head">
              <strong>明细 {{ index + 1 }}</strong>
              <button v-if="form.items.length > 1" class="ghost-button danger-ghost" type="button" @click="removeRow(index)">
                删除
              </button>
            </div>

            <div class="double-field">
              <label class="form-field">
                <span>序号 <i class="required-mark">*</i></span>
                <input v-model.number="item.seq_no" type="number" min="1" step="1" required />
              </label>
              <label class="form-field">
                <span>原材料 <i class="required-mark">*</i></span>
                <select v-model.number="item.material_item_id" required>
                  <option disabled value="">请选择原材料</option>
                  <option v-for="material in materials" :key="material.item_id" :value="material.item_id">
                    {{ material.item_code }} · {{ material.item_name }}
                  </option>
                </select>
              </label>
            </div>

	            <label class="form-field">
	              <span>损耗率</span>
	              <input v-model.number="item.loss_rate" type="number" min="0" step="0.0001" />
	            </label>

	            <div class="triple-field">
	              <label class="form-field">
	                <span>单件净重(kg)</span>
	                <input v-model.number="item.net_weight_per_piece_kg" type="number" min="0" step="0.001" />
              </label>
              <label class="form-field">
                <span>单件毛重(kg) <i class="required-mark">*</i></span>
                <input v-model.number="item.gross_weight_per_piece_kg" type="number" min="0.001" step="0.001" required />
              </label>
              <label class="form-field">
                <span>超发容差率</span>
	                <input v-model.number="item.issue_over_tolerance_rate" type="number" min="0" step="0.0001" />
	              </label>
	            </div>

            <label class="form-field">
              <span>备注</span>
              <input v-model.trim="item.remark" type="text" />
            </label>
          </article>
        </div>

        <div class="form-toolbar">
          <button class="primary-button" type="submit" :disabled="submitting">
            {{ submitting ? "保存中..." : editingBomId ? "更新BOM" : "新增BOM" }}
          </button>
        </div>
      </form>
    </FormDrawer>

    <FormDrawer
      :open="detailDrawerOpen"
      eyebrow="BOM详情"
      :title="detailBom ? `${detailBom.bom_code} · ${detailBom.version_no}` : 'BOM详情'"
      tag="只读详情"
      size="xl"
      @close="closeDetailDrawer"
    >
      <div v-if="detailBom" class="detail-grid">
        <div class="detail-item">
          <span>BOM编码</span>
          <strong>{{ detailBom.bom_code }}</strong>
        </div>
        <div class="detail-item">
          <span>产品</span>
          <strong>{{ formatProductLabel(detailBom) }}</strong>
        </div>
        <div class="detail-item">
          <span>版本号</span>
          <strong>{{ detailBom.version_no }}</strong>
        </div>
        <div class="detail-item">
          <span>默认版本</span>
          <strong>{{ detailBom.is_default ? "是" : "否" }}</strong>
        </div>
        <div class="detail-item">
          <span>状态</span>
          <strong>{{ formatStatusLabel(detailBom.status) }}</strong>
        </div>
        <div class="detail-item">
          <span>明细数</span>
          <strong>{{ detailBom.item_count }}</strong>
        </div>
        <div class="detail-block">
          <span>备注</span>
          <strong>{{ detailBom.remark || "-" }}</strong>
        </div>
        <div class="detail-block">
          <span>BOM明细</span>
          <DrawerDataTable
            v-model:expanded-rows="expandedBomItemRows"
            :rows="paginatedDetailBomItems"
            :columns="bomItemDrawerColumns"
            :row-key="bomItemRowKey"
            empty-text="暂无BOM明细"
          >
            <template #cell-material_summary="{ row }">
              <span class="drawer-cell-ellipsis" :title="`${row.material_code || ''} · ${row.material_name || ''}`">
                {{ row.material_code || "-" }} · {{ row.material_name || "-" }}
              </span>
            </template>
            <template #detail="{ row }">
              <div class="drawer-row-detail-grid">
                <article><span>原材料</span><strong>{{ row.material_code || "-" }} · {{ row.material_name || "-" }}</strong></article>
                <article><span>单件净重</span><strong>{{ formatWeight(row.net_weight_per_piece_kg) }}</strong></article>
                <article><span>超发容差率</span><strong>{{ formatRate(row.issue_over_tolerance_rate) }}</strong></article>
                <article><span>备注</span><strong>{{ row.remark || "-" }}</strong></article>
              </div>
            </template>
          </DrawerDataTable>
          <PaginationBar
            v-model:page="detailBomItemPage"
            :total="detailBomItems.length"
            v-model:page-size="detailBomItemPageSize"
          />
        </div>
      </div>
    </FormDrawer>
  </section>
</template>

<script setup>
import { computed, onMounted, reactive, ref, watch } from "vue";

import DrawerDataTable from "../components/DrawerDataTable.vue";
import FormDrawer from "../components/FormDrawer.vue";
import PaginationBar from "../components/PaginationBar.vue";
import TableControls from "../components/TableControls.vue";
import { deleteResource, fetchResource, postResource, putResource } from "../services/api";
import { buildBomCodePreview } from "../utils/codeRules";
import { formatWeight } from "../utils/formatters";
import {
  STATUS_LABELS,
  buildVersionedRows,
  formatProductLabel,
  formatStatusLabel
} from "../utils/dictionaries";
import { usePagination } from "../utils/pagination";
import { useTableControls } from "../utils/tableControls";

const boms = ref([]);
const products = ref([]);
const materials = ref([]);
const editingBomId = ref(null);
const selectedBomId = ref(null);
const drawerOpen = ref(false);
const detailDrawerOpen = ref(false);
const detailBom = ref(null);
const expandedBomItemRows = ref([]);
const submitting = ref(false);
const feedbackMessage = ref("");
const errorMessage = ref("");
const versionSelections = reactive({});

const today = new Date().toISOString().slice(0, 10);
const form = reactive(buildEmptyForm());

const statusOptions = [
  { value: "ACTIVE", label: STATUS_LABELS.ACTIVE },
  { value: "INACTIVE", label: STATUS_LABELS.INACTIVE }
];
const bomGroups = computed(() => buildVersionedRows(boms.value, { codeKey: "bom_code", idKey: "bom_id" }));
const selectedProduct = computed(() => products.value.find((item) => item.item_id === Number(form.product_item_id || 0)) || null);
const bomCodePreview = computed(() => buildBomCodePreview(selectedProduct.value?.item_code, form.bom_code));
const visibleBoms = computed(() =>
  bomGroups.value.map((group) => {
    const selectedId = Number(versionSelections[group.code] || group.active_id);
    const activeRow = group.rows.find((row) => row.bom_id === selectedId) || group.rows[0];
    return {
      ...activeRow,
      version_options: group.rows.map((row) => ({
        bom_id: row.bom_id,
        version_no: row.version_no,
        status: row.status,
        is_default: row.is_default
      }))
    };
  })
);
const bomControls = useTableControls(visibleBoms, {
  searchFields: ["bom_code", "product_code", "product_name", "version_no", "status"],
  sortOptions: [
    { key: "bom_code", label: "BOM编码" },
    { key: "product_name", label: "产品" },
    { key: "version_no", label: "版本" },
    { key: "item_count", label: "明细数" },
    { key: "status", label: "状态" }
  ],
  defaultSortKey: "bom_code",
  defaultSortDirection: "asc"
});
const currentBom = computed(() => boms.value.find((item) => item.bom_id === selectedBomId.value) || null);
const currentBomItems = computed(() => currentBom.value?.items || []);
const detailBomItems = computed(() => detailBom.value?.items || []);
const filteredBoms = bomControls.rows;
const bomItemDrawerColumns = computed(() => [
  { key: "seq_no", label: "序号", type: "number", width: "70px" },
  { key: "material_summary", label: "原材料", type: "longText", width: "42%" },
  { key: "gross_weight_per_piece_kg", label: "单件毛重", type: "number", width: "112px", format: (value) => formatWeight(value) },
  { key: "loss_rate", label: "损耗率", type: "number", width: "96px", format: (value) => formatRate(value) },
  { key: "net_weight_per_piece_kg", label: "单件净重", detailOnly: true, format: (value) => formatWeight(value) },
  { key: "issue_over_tolerance_rate", label: "超发容差率", detailOnly: true, format: (value) => formatRate(value) },
  { key: "remark", label: "备注", detailOnly: true }
]);
const {
  page: bomPage,
  pageSize: bomPageSize,
  rows: paginatedBoms
} = usePagination(filteredBoms);
const {
  page: detailBomItemPage,
  pageSize: detailBomItemPageSize,
  rows: paginatedDetailBomItems
} = usePagination(detailBomItems);

function getDefaultNetWeight() {
  return Number(selectedProduct.value?.unit_weight_kg || 0);
}

function buildEmptyItem(seqNo = 10, defaultNetWeight = 0) {
  return {
    seq_no: seqNo,
    material_item_id: "",
    usage_type: "WEIGHT",
    qty_per_piece: 1,
    net_weight_per_piece_kg: Number(defaultNetWeight || 0),
    gross_weight_per_piece_kg: 0,
    loss_rate: 0,
    issue_over_tolerance_rate: 0,
    remark: ""
  };
}

function buildEmptyForm() {
  return {
    bom_code: "",
    product_item_id: "",
    version_no: "V1.0",
    is_default: true,
    status: "ACTIVE",
    effective_date: today,
    remark: "",
    items: [buildEmptyItem(10, 0)]
  };
}

function resetForm() {
  editingBomId.value = null;
  Object.assign(form, buildEmptyForm());
}

function openCreateDrawer() {
  feedbackMessage.value = "";
  errorMessage.value = "";
  resetForm();
  drawerOpen.value = true;
}

function closeDrawer() {
  drawerOpen.value = false;
  resetForm();
}

function openDetailDrawer(bom) {
  selectedBomId.value = bom.bom_id;
  detailBom.value = { ...bom, items: [...(bom.items || [])] };
  expandedBomItemRows.value = [];
  detailDrawerOpen.value = true;
}

function closeDetailDrawer() {
  detailDrawerOpen.value = false;
  detailBom.value = null;
}

function addRow() {
  const nextSeq = form.items.length ? Math.max(...form.items.map((item) => Number(item.seq_no || 0))) + 10 : 10;
  form.items.push(buildEmptyItem(nextSeq, getDefaultNetWeight()));
}

function removeRow(index) {
  form.items.splice(index, 1);
}

function applyBomVersion(bomCode) {
  selectedBomId.value = Number(versionSelections[bomCode] || 0);
}

function startEdit(bom) {
  feedbackMessage.value = "";
  errorMessage.value = "";
  editingBomId.value = bom.bom_id;
  selectedBomId.value = bom.bom_id;
  versionSelections[bom.bom_code] = bom.bom_id;
  Object.assign(form, {
    bom_code: bom.bom_code,
    product_item_id: bom.product_item_id,
    version_no: bom.version_no,
    is_default: Boolean(bom.is_default),
    status: bom.status,
    effective_date: bom.effective_date || today,
    remark: bom.remark || "",
    items: (bom.items || []).map((item) => ({
      seq_no: Number(item.seq_no),
      material_item_id: item.material_item_id,
      usage_type: item.usage_type,
      qty_per_piece: Number(item.qty_per_piece || 0),
      net_weight_per_piece_kg: Number(item.net_weight_per_piece_kg || 0),
      gross_weight_per_piece_kg: Number(item.gross_weight_per_piece_kg || 0),
      loss_rate: Number(item.loss_rate || 0),
      issue_over_tolerance_rate: Number(item.issue_over_tolerance_rate || 0),
      remark: item.remark || ""
    }))
  });
  drawerOpen.value = true;
}

function formatRate(value) {
  return `${(Number(value || 0) * 100).toFixed(2)}%`;
}

function bomItemRowKey(row) {
  return `${detailBom.value?.bom_id || "bom"}-${row.seq_no}`;
}

function syncVersionSelections(rows) {
  const groups = buildVersionedRows(rows, { codeKey: "bom_code", idKey: "bom_id" });
  const validCodes = new Set(groups.map((group) => group.code));
  Object.keys(versionSelections).forEach((code) => {
    if (!validCodes.has(code)) {
      delete versionSelections[code];
    }
  });
  groups.forEach((group) => {
    const currentSelection = Number(versionSelections[group.code] || 0);
    if (!group.rows.some((row) => row.bom_id === currentSelection)) {
      versionSelections[group.code] = group.active_id;
    }
  });
}

async function loadAll() {
  const [bomRows, productRows, materialRows] = await Promise.all([
    fetchResource("/master-data/boms", []),
    fetchResource("/master-data/products", []),
    fetchResource("/master-data/materials", [])
  ]);
  boms.value = bomRows;
  products.value = productRows;
  materials.value = materialRows;
  syncVersionSelections(bomRows);
  if (selectedBomId.value && !bomRows.some((item) => item.bom_id === selectedBomId.value)) {
    selectedBomId.value = null;
  }
  if (!selectedBomId.value && visibleBoms.value.length) {
    selectedBomId.value = visibleBoms.value[0].bom_id;
  }
}

async function submitBom() {
  feedbackMessage.value = "";
  errorMessage.value = "";
  submitting.value = true;

  try {
    const payload = {
      bom_code: form.bom_code || null,
      product_item_id: Number(form.product_item_id),
      version_no: form.version_no,
      is_default: Boolean(form.is_default),
      status: form.status,
      effective_date: form.effective_date || null,
      expire_date: null,
      remark: form.remark || null,
      items: form.items.map((item) => ({
        seq_no: Number(item.seq_no),
        material_item_id: Number(item.material_item_id),
        usage_type: "WEIGHT",
        qty_per_piece: 1,
        net_weight_per_piece_kg: Number(item.net_weight_per_piece_kg || 0),
        gross_weight_per_piece_kg: Number(item.gross_weight_per_piece_kg || 0),
        loss_rate: Number(item.loss_rate || 0),
        issue_over_tolerance_rate: Number(item.issue_over_tolerance_rate || 0),
        remark: item.remark || null
      }))
    };

    const result = editingBomId.value
      ? await putResource(`/master-data/boms/${editingBomId.value}`, payload)
      : await postResource("/master-data/boms", payload);

    feedbackMessage.value = `BOM ${result.bom_code} ${result.version_no} 已保存`;
    await loadAll();
    selectedBomId.value = result.bom_id;
    versionSelections[result.bom_code] = result.bom_id;
    resetForm();
    drawerOpen.value = false;
  } catch (error) {
    errorMessage.value = error.message || "保存BOM失败";
  } finally {
    submitting.value = false;
  }
}

async function removeBom(bom) {
  feedbackMessage.value = "";
  errorMessage.value = "";

  if (!window.confirm(`确认删除BOM“${bom.bom_code} ${bom.version_no}”吗？`)) {
    return;
  }

  try {
    const result = await deleteResource(`/master-data/boms/${bom.bom_id}`);
    feedbackMessage.value = result.message || `BOM ${bom.bom_code} 已删除`;
    if (editingBomId.value === bom.bom_id) {
      resetForm();
      drawerOpen.value = false;
    }
    if (selectedBomId.value === bom.bom_id) {
      selectedBomId.value = null;
    }
    await loadAll();
  } catch (error) {
    errorMessage.value = error.message || "删除BOM失败";
  }
}

onMounted(async () => {
  await loadAll();
});

watch(
  () => form.product_item_id,
  () => {
    const defaultNetWeight = getDefaultNetWeight();
    form.items.forEach((item) => {
      if (Number(item.net_weight_per_piece_kg || 0) <= 0) {
        item.net_weight_per_piece_kg = defaultNetWeight;
      }
    });
  }
);
</script>
