<script setup lang="ts">
import { computed, nextTick, onMounted, ref } from 'vue'
import { useRoute } from 'vue-router'
import type { KbxLookupItem } from '@kbx/contracts'
import { kbxFieldReadonly, resolveKbxRecordStatePolicy } from '@kbx/contracts'
import {
  KbxButton,
  KbxDataGrid,
  KbxDateField,
  KbxFormGrid,
  KbxFormSection,
  KbxFormSpan,
  KbxInput,
  KbxLookup,
  KbxLookupDialog,
  KbxTransactionPage,
  KbxUnsavedChangesDialog,
  useKbxPageShortcuts,
  resolveKbxGridStatus,
} from '@kbx/ui'
import {
  orderLineColumns,
  orderRegisterScreen,
  orderStatePolicies,
  orderWorkflow,
  type OrderLineForm,
} from './order-register.definition'
import { useKbxWorkspaceBinding } from '../../../../shell/useKbxWorkspaceBinding'
import { useOrderRegistration } from './useOrderRegistration'
import { kbxStatusCatalog } from '../../../../registry/statusCatalog'

const route = useRoute()
const vm = useOrderRegistration()
useKbxWorkspaceBinding(vm.dirty, async () => Boolean(await vm.save()))

const detailGrid = ref<any>(null)
const itemLookupOpen = ref(false)
const activeLine = ref<OrderLineForm | null>(null)
const activeLookupField = ref<keyof OrderLineForm & string>('itemCode')
const pendingReset = ref<'new' | 'copy' | null>(null)
const savingReset = ref(false)

const statePolicy = computed(() => resolveKbxRecordStatePolicy(orderStatePolicies, vm.status.value))
const readonly = computed(() => statePolicy.value.editability === 'readonly')
const displayStatus = computed(() => resolveKbxGridStatus({definitions:kbxStatusCatalog.orderLifecycle}, vm.status.value))
const summaryItems = computed(() => [
  { key:'items', label:'품목', value:`${vm.lines.value.length.toLocaleString('ko-KR')}종` },
  { key:'qty', label:'총수량', value:vm.totalQty.value },
  { key:'amount', label:'주문금액', value:`₩${vm.totalAmount.value.toLocaleString('ko-KR')}`, emphasis:true },
])
const pageContext = computed(() => ({
  label: vm.orderNo.value ? `주문 ${vm.orderNo.value}` : '신규 주문',
  hint: vm.dirty.value ? '저장하지 않은 변경사항이 있습니다.' : `${displayStatus.value.label} 상태`,
  metrics: [
    { key:'status', label:'상태', value:displayStatus.value.label },
    { key:'lines', label:'상품', value:vm.lines.value.length },
    { key:'errors', label:'오류', value:vm.errors.value.length, tone:'danger' as const, emphasis:vm.errors.value.length > 0 },
  ],
}))

function fieldReadonly(field:string) {
  return kbxFieldReadonly(statePolicy.value, field)
}

function openGridLookup(event:{ row:OrderLineForm; field:keyof OrderLineForm & string; entity:string }) {
  if (event.entity !== 'item' || readonly.value) return
  activeLine.value = event.row
  activeLookupField.value = event.field
  itemLookupOpen.value = true
}


async function addLineAndFocus() {
  if (readonly.value) return
  vm.addLine()
  const line = vm.lines.value.at(-1)
  if (!line) return
  await nextTick()
  detailGrid.value?.focusCell?.(line.clientId, 'itemCode')
}

function focusNextError() {
  detailGrid.value?.focusError?.(1)
}

async function selectGridItem(item:KbxLookupItem<string>) {
  const line = activeLine.value
  if (!line) return
  vm.applyItemLookup(line, item)
  itemLookupOpen.value = false
  await nextTick()
  detailGrid.value?.focusNextEditableCell?.(line.clientId, activeLookupField.value)
}

function applyReset(kind:'new' | 'copy') {
  if (kind === 'new') vm.createNew()
  else vm.copyCurrent()
  pendingReset.value = null
}

function requestReset(kind:'new' | 'copy') {
  if (readonly.value && kind === 'copy') {
    applyReset(kind)
    return
  }
  if (vm.dirty.value) {
    pendingReset.value = kind
    return
  }
  applyReset(kind)
}

async function saveThenReset() {
  const kind = pendingReset.value
  if (!kind) return
  savingReset.value = true
  try {
    if (await vm.save()) applyReset(kind)
  } finally {
    savingReset.value = false
  }
}

async function executeCommand(id:string) {
  if (id === 'save') await vm.save()
  else if (id === 'new') requestReset('new')
  else if (id === 'copy') requestReset('copy')
  else if (id === 'confirm') await vm.confirm()
}

useKbxPageShortcuts([{ key:'F8', execute:() => vm.save() }])

onMounted(async () => {
  const id = String(route.params.orderId ?? '')
  if (id) await vm.load(id)
})
</script>

<template>
  <KbxTransactionPage
    :screen="orderRegisterScreen"
    :status="vm.status.value"
    :dirty="vm.dirty.value"
    :version="vm.version.value"
    :errors="vm.errors.value"
    :workflow="orderWorkflow"
    :conflict="vm.conflict.value"
    :problem="vm.problem.value"
    :audit-entries="vm.auditEntries.value"
    :summary-items="summaryItems"
    :context="pageContext"
    header-title="주문 정보"
    header-description="주문 조건과 배송 기준을 먼저 확인한 뒤 상품 상세를 입력합니다."
    detail-title="주문 상품"
    :detail-count="vm.lines.value.length"
    detail-count-unit="종"
    detail-description="Enter 연속입력, F2 품목 조회, Excel 붙여넣기 문법을 동일하게 사용합니다."
    breadcrumb="OMS > 주문"
    @command="executeCommand"
    @transition="executeCommand"
    @reload-conflict="vm.reloadConflict"
    @dismiss-conflict="vm.dismissConflict"
    @retry-problem="vm.retryProblem"
    @dismiss-problem="vm.dismissProblem"
  >
    <template #header>
      <KbxFormSection title="기본정보">
        <KbxFormGrid>
          <KbxDateField v-model="vm.header.orderDate" label="주문일" required :readonly="fieldReadonly('orderDate')" :error="vm.fieldError('orderDate')" @update:model-value="vm.touch" />
          <KbxLookup v-model="vm.header.customerId" entity="customer" label="거래처" required :readonly="fieldReadonly('customerId')" :error="vm.fieldError('customerId')" @selected="vm.touch" />
          <KbxLookup v-model="vm.header.warehouseId" entity="warehouse" label="출고창고" required :readonly="fieldReadonly('warehouseId')" :error="vm.fieldError('warehouseId')" @selected="vm.touch" />
          <KbxInput v-model="vm.header.receiverName" label="수취인" required :readonly="fieldReadonly('receiverName')" :error="vm.fieldError('receiverName')" @update:model-value="vm.touch" />
          <KbxInput v-model="vm.header.phone" label="연락처" required :readonly="fieldReadonly('phone')" :error="vm.fieldError('phone')" @update:model-value="vm.touch" />
        </KbxFormGrid>
      </KbxFormSection>

      <KbxFormSection title="배송정보">
        <KbxFormGrid>
          <KbxInput v-model="vm.header.postalCode" label="우편번호" :readonly="fieldReadonly('postalCode')" @update:model-value="vm.touch" />
          <KbxFormSpan span="full"><KbxInput v-model="vm.header.address1" label="주소" required :readonly="fieldReadonly('address1')" :error="vm.fieldError('address1')" @update:model-value="vm.touch" /></KbxFormSpan>
          <KbxFormSpan span="full"><KbxInput v-model="vm.header.address2" label="상세주소" :readonly="fieldReadonly('address2')" @update:model-value="vm.touch" /></KbxFormSpan>
        </KbxFormGrid>
      </KbxFormSection>
    </template>

    <template #detail-actions>
      <KbxButton v-if="vm.errors.value.length" label="첫/다음 오류" variant="ghost" @click="focusNextError" />
      <KbxButton v-if="!readonly" label="행 추가" variant="secondary" @click="addLineAndFocus" />
    </template>

    <template #detail>
      <section class="order-lines">
        <KbxDataGrid
          ref="detailGrid"
          :rows="vm.lines.value"
          :columns="orderLineColumns"
          row-key="clientId"
          aria-label="주문 상품"
          selection="multiple"
          :errors="vm.errors.value"
          :editable="!readonly"
          :editing-policy="{ allowRowAdd:true, allowRowDuplicate:true, fillDown:true, paste:true, errorNavigation:true }"
          @row-add-requested="vm.addLine"
          @row-duplicate-requested="vm.duplicateLines"
          @cell-changed="vm.onCellChanged"
          @lookup-requested="openGridLookup"
        />
      </section>
    </template>
  </KbxTransactionPage>

  <KbxLookupDialog
    v-model:visible="itemLookupOpen"
    entity="item"
    title="품목"
    @select="selectGridItem"
  />

  <KbxUnsavedChangesDialog
    :open="Boolean(pendingReset)"
    :saving="savingReset"
    @stay="pendingReset=null"
    @discard="pendingReset && applyReset(pendingReset)"
    @save="saveThenReset"
  />
</template>

<style scoped>
.order-lines {
  min-height:var(--kbx-grid-min-height);
  display:flex;
  flex-direction:column;
  gap:var(--kbx-space-2);
}
</style>
