<script setup lang="ts">
import { computed, nextTick, ref } from 'vue'
import { isKbxProblem, type KbxProblem } from '@kbx/contracts'
import { useQuery } from '@tanstack/vue-query'
import {
  KbxButton,
  KbxDataGrid,
  KbxExceptionCenter,
  KbxSearchPanel,
  KbxWorkQueuePage,
  useKbxPageShortcuts,
  type KbxWorkItem,
  type KbxWorkItemAction,
} from '@kbx/ui'
import { operationsApi, type OperationsFilter } from './operationsApi'
import { kbxTelemetry } from '../../../telemetry/kbxTelemetryClient'
import { operationsColumns, operationsQueueScreen, operationsSearchFields } from './operations.definition'

const searchModel = ref<Record<string, unknown>>({ status: 'open' })
const applied = ref<OperationsFilter>({ status: 'open', page: 1, pageSize: 200 })
const selectedRows = ref<KbxWorkItem[]>([])
const detail = ref<KbxWorkItem | null>(null)
const quickCode = ref<string | null>(null)
const problem=ref<KbxProblem|null>(null)
const actionReceipt=ref<{kind:'claim'|'resolve';requested:number;succeeded:number;skipped:number}|null>(null)
const actionReceiptEl=ref<HTMLElement|null>(null)
let retryAction:(()=>Promise<void>)|null=null
const query = useQuery({
  queryKey: computed(() => ['operations', 'work-items', applied.value]),
  queryFn: () => operationsApi.search(applied.value),
})

const visibleItems = computed(() => query.data.value?.items ?? [])
const criticalVisible = computed(() => visibleItems.value.filter(item => item.severity === 'critical' && item.status !== 'resolved').length)
const unassignedVisible = computed(() => visibleItems.value.filter(item => !item.ownerId && item.status !== 'resolved').length)
const agedVisible = computed(() => visibleItems.value.filter(item => item.ageMinutes >= 60 && item.status !== 'resolved').length)
const nextUrgent = computed(() => visibleItems.value.find(item => item.severity === 'critical' && item.status !== 'resolved') ?? null)
const pageContext=computed(()=>({
  label:'예외 업무 Queue',
  hint:'정상 건은 제외하고 해결이 필요한 업무만 표시합니다.',
  metrics:[
    {key:'total',label:'대상',value:query.data.value?.totalCount??0},
    {key:'critical',label:'표시 긴급',value:criticalVisible.value,tone:'danger' as const,emphasis:criticalVisible.value>0},
    {key:'unassigned',label:'표시 미지정',value:unassignedVisible.value,tone:'warning' as const},
    {key:'aged',label:'표시 60분+',value:agedVisible.value,tone:'warning' as const},
    {key:'selected',label:'선택',value:selectedRows.value.length},
  ],
}))

useKbxPageShortcuts([{ key: 'F3', execute: () => search() }])

async function search() {
  problem.value=null; retryAction=null
  selectedRows.value = []
  actionReceipt.value = null
  applied.value = {
    module: asString(searchModel.value.module),
    severity: asString(searchModel.value.severity),
    status: asString(searchModel.value.status),
    owner: asString(searchModel.value.owner),
    keyword: asString(searchModel.value.keyword),
    code: quickCode.value,
    page: 1,
    pageSize: 200,
  }
  await query.refetch()
}

function asString(value: unknown) { return value == null || value === '' ? null : String(value) }

async function selectQuickFilter(code: string | null) {
  quickCode.value = code
  await search()
}

async function showMine() {
  searchModel.value = { ...searchModel.value, owner: 'mine', status: searchModel.value.status || 'open' }
  await search()
}

function openNextUrgent() {
  if (nextUrgent.value) detail.value = nextUrgent.value
}

async function runProblemAware(action:()=>Promise<void>){
  problem.value=null; retryAction=null
  try{await action()}catch(error){if(isKbxProblem(error)){problem.value=error;retryAction=()=>runProblemAware(action);return}throw error}
}
async function executeCommand(id: string) {
  const ids = selectedRows.value.map(x => x.id)
  if (id === 'search') return search()
  if (id === 'claim' && ids.length) return runProblemAware(async()=>{
    const result=await operationsApi.claim(ids)
    actionReceipt.value={kind:'claim',requested:ids.length,succeeded:result.claimedCount,skipped:result.skippedCount}
    selectedRows.value=[]
    await query.refetch()
    await nextTick(); actionReceiptEl.value?.focus({preventScroll:true})
  })
}

async function executeAction(action: KbxWorkItemAction) {
  if (!detail.value) return
  const item=detail.value
  if(action.kind==='navigate'){window.dispatchEvent(new CustomEvent('kbx:navigate-source',{detail:item}));detail.value=null;return}
  await runProblemAware(async()=>{
    if (action.kind === 'claim') {
      const result=await operationsApi.claim([item.id])
      actionReceipt.value={kind:'claim',requested:1,succeeded:result.claimedCount,skipped:result.skippedCount}
    }
    if (action.kind === 'resolve') {
      const result=await operationsApi.resolve([item.id])
      actionReceipt.value={kind:'resolve',requested:1,succeeded:result.resolvedCount,skipped:result.rejectedCount}
      if(result.resolvedCount>0){
        kbxTelemetry.track('exception.resolved',{screenId:operationsQueueScreen.id,screenVersion:operationsQueueScreen.version,durationMs:Math.max(0,item.ageMinutes*60000),attributes:{exceptionType:item.code,resolutionType:'manual'}})
      }
    }
    if (action.kind === 'retry') await operationsApi.retry(item.id)
    detail.value = null
    await query.refetch()
    if(actionReceipt.value){await nextTick();actionReceiptEl.value?.focus({preventScroll:true})}
  })
}
async function retryProblem(){const retry=retryAction;problem.value=null;retryAction=null;if(retry)await retry()}
function dismissProblem(){problem.value=null;retryAction=null}
</script>

<template>
  <KbxWorkQueuePage
    :screen="operationsQueueScreen"
    :selection-count="selectedRows.length"
    :context="pageContext"
    :content-state="query.error.value?'error':query.isFetching.value&&!query.data.value?'loading':query.data.value?.totalCount===0?'empty':'ready'"
    :refreshing="query.isFetching.value&&Boolean(query.data.value)"
    :problem="problem"
    queue-title="예외 업무 Queue"
    queue-description="긴급도·담당자·경과시간을 먼저 확인하고 상세 Drawer에서 원인과 다음 행동을 처리합니다."
    :queue-count="query.data.value?.totalCount ?? 0"
    empty-title="처리할 예외 업무가 없습니다."
    empty-detail="현재 조건에는 사람이 확인해야 할 예외가 없습니다. 조건을 바꾸거나 전체 미처리 업무를 조회하세요."
    @command="executeCommand"
    @retry-problem="retryProblem"
    @dismiss-problem="dismissProblem"
  >
    <template #search>
      <KbxSearchPanel v-model="searchModel" :fields="operationsSearchFields" @search="search" />
    </template>

    <template #queue-summary>
      <span class="queue-hint">정상 건은 표시하지 않습니다. 중요도와 경과시간이 높은 예외부터 처리합니다.</span>
    </template>

    <template #queue-actions>
      <KbxButton label="내 업무" variant="secondary" @click="showMine" />
      <KbxButton label="다음 긴급건" variant="secondary" :disabled="!nextUrgent" @click="openNextUrgent" />
    </template>

    <template #content>
      <section v-if="actionReceipt" ref="actionReceiptEl" class="bulk-receipt" :data-result="actionReceipt.skipped>0?'partial':'success'" role="status" aria-live="polite" tabindex="-1" data-kbx-surface="authoritative-action-receipt">
        <div>
          <strong>{{ actionReceipt.kind==='claim'
            ? (actionReceipt.skipped>0 ? '담당 지정이 일부 처리되었습니다.' : '담당 지정을 완료했습니다.')
            : (actionReceipt.skipped>0 ? '해결 처리가 완료되지 않았습니다.' : '해결 처리를 완료했습니다.') }}</strong>
          <span v-if="actionReceipt.kind==='claim'">요청 {{ actionReceipt.requested.toLocaleString('ko-KR') }}건 · 내 업무 전환 {{ actionReceipt.succeeded.toLocaleString('ko-KR') }}건 · 건너뜀 {{ actionReceipt.skipped.toLocaleString('ko-KR') }}건</span>
          <span v-else>요청 {{ actionReceipt.requested.toLocaleString('ko-KR') }}건 · 해결 {{ actionReceipt.succeeded.toLocaleString('ko-KR') }}건 · 거절 {{ actionReceipt.skipped.toLocaleString('ko-KR') }}건</span>
          <small v-if="actionReceipt.skipped>0">HTTP 성공 여부가 아니라 서버 업무 결과를 기준으로 표시합니다. 최신 상태를 다시 조회해 다음 행동을 결정하세요.</small>
        </div>
        <div class="bulk-receipt__actions">
          <KbxButton v-if="actionReceipt.kind==='claim' && actionReceipt.succeeded>0" label="내 업무 보기" variant="secondary" @click="showMine" />
          <KbxButton v-if="actionReceipt.skipped>0" label="최신 상태 조회" variant="secondary" @click="search" />
          <KbxButton label="결과 닫기" variant="ghost" @click="actionReceipt=null" />
        </div>
      </section>

      <KbxExceptionCenter
        :counters="query.data.value?.counters ?? []"
        :active-key="quickCode"
        :selected-item="detail"
        @filter="selectQuickFilter"
        @close-detail="detail = null"
        @action="executeAction"
      >
        <KbxDataGrid
          :rows="query.data.value?.items ?? []"
          :columns="operationsColumns"
          row-key="id"
          selection="multiple"
          :loading="query.isFetching.value"
          @selection-changed="selectedRows = $event"
          @row-double-clicked="detail = $event"
        />
      </KbxExceptionCenter>
    </template>

    <template #footer>
      전체 {{ query.data.value?.totalCount ?? 0 }}건 · 선택 {{ selectedRows.length }}건
    </template>

  </KbxWorkQueuePage>
</template>

<style scoped>
.bulk-receipt{display:flex;align-items:center;justify-content:space-between;gap:var(--kbx-space-3);margin-bottom:var(--kbx-space-3);padding:var(--kbx-space-2) var(--kbx-space-3);border:var(--kbx-border-width) solid var(--kbx-color-success-border);border-left:var(--kbx-accent-border-width) solid var(--kbx-color-success-border);background:var(--kbx-color-success-surface);font-size:var(--kbx-font-sm)}
.bulk-receipt[data-result="partial"]{border-color:var(--kbx-color-warning-border);border-left-color:var(--kbx-color-warning-border);background:var(--kbx-color-warning-surface)}
.bulk-receipt>div:first-child{display:grid;gap:var(--kbx-space-1)}.bulk-receipt span,.bulk-receipt small{color:var(--kbx-color-text-muted)}.bulk-receipt__actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--kbx-space-2)}
@media(max-width:60rem){.bulk-receipt{align-items:stretch;flex-direction:column}.bulk-receipt__actions{justify-content:flex-start}}
@media(forced-colors:active){.bulk-receipt,.bulk-receipt[data-result="partial"]{border-color:CanvasText;border-left-color:Highlight}}
</style>
