<script setup lang="ts">
import { computed, inject, ref } from 'vue'
import type { KbxWorkflowDefinition, KbxWorkflowTransitionDefinition } from '@kbx/contracts'
import KbxButton from './KbxButton.vue'
import KbxConfirm from './KbxConfirm.vue'
import KbxStatus from './KbxStatus.vue'
import { KbxPermissionHostKey } from '../permission/host'
const props=defineProps<{workflow:KbxWorkflowDefinition;current:string;can?:(permission:string)=>boolean}>();const emit=defineEmits<{transition:[string]}>();const pending=ref<KbxWorkflowTransitionDefinition|null>(null);const permissionHost=inject(KbxPermissionHostKey,null)
function canPermission(permission:string){return props.can?props.can(permission):(permissionHost?.has(permission)??true)}
const currentState=computed(()=>props.workflow.states.find(x=>x.value===props.current));const actions=computed(()=>props.workflow.transitions.filter(x=>x.from.includes(props.current)&&(!x.permission||canPermission(x.permission))))
const currentIndex=computed(()=>Math.max(props.workflow.states.findIndex(state=>state.value===props.current),0))
const progressLabel=computed(()=>`${Math.min(currentIndex.value+1,props.workflow.states.length)} / ${props.workflow.states.length}`)
const nextActionLabel=computed(()=>actions.value.length?actions.value.map(action=>action.label).join(' · '):'현재 상태에서 실행 가능한 다음 작업이 없습니다.')
function invoke(action:KbxWorkflowTransitionDefinition){if(action.confirm){pending.value=action;return}emit('transition',action.id)}function confirm(){if(!pending.value)return;const id=pending.value.id;pending.value=null;emit('transition',id)}
</script>
<template><section class="kbx-workflow-bar" aria-label="업무 상태"><div class="kbx-workflow-bar__state"><span class="label">현재 상태</span><KbxStatus v-if="currentState" :label="currentState.label" :semantic="currentState.semantic"/><strong v-else>{{current}}</strong><small>{{progressLabel}}</small></div><div class="kbx-workflow-bar__flow" aria-label="상태 흐름"><template v-for="(state,i) in workflow.states" :key="state.value"><span :class="['step',{current:state.value===current,passed:i<currentIndex}]" :aria-current="state.value===current?'step':undefined">{{state.label}}</span><span v-if="i<workflow.states.length-1" class="arrow">→</span></template></div><div class="kbx-workflow-bar__next"><small>다음 작업</small><strong>{{nextActionLabel}}</strong></div><div class="kbx-workflow-bar__actions"><KbxButton v-for="action in actions" :key="action.id" :label="action.label" @click="invoke(action)"/></div><KbxConfirm v-if="pending" :open="Boolean(pending)" :title="`${pending.label}하시겠습니까?`" :detail="`${currentState?.label??current} 상태에서 ${workflow.states.find(x=>x.value===pending?.to)?.label??pending.to} 상태로 변경합니다.`" level="high" :confirm-label="pending.label" @update:open="value=>{if(!value)pending=null}" @confirm="confirm"/></section></template>
<style scoped>.kbx-workflow-bar{display:grid;grid-template-columns:auto minmax(0,1fr) auto;grid-template-areas:'state flow actions' 'next next next';gap:var(--kbx-space-2) var(--kbx-space-3);align-items:center;min-height:var(--kbx-command-bar-height);padding:var(--kbx-space-2);border:var(--kbx-border-width) solid var(--kbx-color-border);border-left:var(--kbx-accent-border-width) solid var(--kbx-color-module-accent);background:var(--kbx-color-surface-muted);border-radius:var(--kbx-radius-sm);font-size:var(--kbx-font-sm)}.kbx-workflow-bar__state{grid-area:state;display:flex;align-items:center;gap:var(--kbx-space-2);white-space:nowrap}.kbx-workflow-bar__state small{color:var(--kbx-color-text-muted)}.label,.kbx-workflow-bar__flow{color:var(--kbx-color-text-muted)}.kbx-workflow-bar__flow{grid-area:flow;min-width:0;overflow:auto;display:flex;align-items:center;gap:var(--kbx-space-1);white-space:nowrap}.step.current{color:var(--kbx-color-text);font-weight:700}.step.passed{color:var(--kbx-color-text)}.step.current::before{content:'●';margin-right:var(--kbx-space-1);color:var(--kbx-color-module-accent);font-size:var(--kbx-font-xs)}.arrow{color:var(--kbx-color-border-strong)}.kbx-workflow-bar__next{grid-area:next;min-width:0;display:flex;align-items:center;gap:var(--kbx-space-2);padding-top:var(--kbx-space-1);border-top:var(--kbx-border-width) solid var(--kbx-color-border)}.kbx-workflow-bar__next small{color:var(--kbx-color-text-muted);white-space:nowrap}.kbx-workflow-bar__next strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--kbx-font-xs);font-weight:600}.kbx-workflow-bar__actions{grid-area:actions;display:flex;gap:var(--kbx-space-2)}@media(max-width:68.75rem){.kbx-workflow-bar{grid-template-columns:1fr auto;grid-template-areas:'state actions' 'flow flow' 'next next'}}@media(forced-colors:active){.step.current::before{color:Highlight}}</style>
