<template>
  <div class="expense-memory-settings">
    <section class="settings-card expense-memory-create-card">
      <div class="card-head">
        <div class="card-title-with-icon">
          <div class="model-icon-box slate">
            <i class="mdi mdi-brain"></i>
          </div>
          <div>
            <h4>组织费用申请记忆</h4>
            <p>为企业或指定部门配置出行方式基线，仅用于申请表单的智能填充。</p>
          </div>
        </div>
      </div>

      <div class="expense-memory-safety-note">
        <i class="mdi mdi-shield-check-outline" aria-hidden="true"></i>
        <span>只保存飞机、火车、轮船三种低敏枚举值，不保存金额、事由或客户信息。</span>
      </div>

      <div class="expense-memory-scope-switch" aria-label="选择记忆作用域">
        <button
          v-for="option in scopeOptions"
          :key="option.value"
          type="button"
          :class="{ active: createForm.scopeType === option.value }"
          @click="selectScope(option.value)"
        >
          <strong>{{ option.label }}</strong>
          <span>{{ option.desc }}</span>
        </button>
      </div>

      <div class="expense-memory-form-grid">
        <label v-if="createForm.scopeType === 'department'" class="field">
          <span><em>*</em> 适用部门</span>
          <EnterpriseSelect
            v-model="createForm.scopeId"
            :options="departmentOptions"
            filterable
            placeholder="选择稳定部门 ID"
          />
          <small>部门来自员工组织元数据，不使用可变的部门名称作为关联键。</small>
        </label>

        <label class="field">
          <span><em>*</em> 默认出行方式</span>
          <EnterpriseSelect v-model="createForm.value" :options="transportOptions" />
        </label>

        <label class="field">
          <span><em>*</em> 有效天数</span>
          <input v-model.number="createForm.expiresInDays" type="number" min="30" max="365" />
          <small>30 至 365 天，到期后自动停止填充。</small>
        </label>

        <label class="field field-wide">
          <span><em>*</em> 操作理由</span>
          <input
            v-model="createForm.reason"
            type="text"
            maxlength="255"
            placeholder="例如：统一当前差旅出行基线"
          />
          <small>理由用于后端审计，不会向普通员工展示。</small>
        </label>
      </div>

      <div class="expense-memory-form-actions">
        <button
          class="expense-memory-primary-button"
          type="button"
          :disabled="busyKey === 'create'"
          @click="createMemory"
        >
          <i :class="busyKey === 'create' ? 'mdi mdi-loading mdi-spin' : 'mdi mdi-plus-circle-outline'"></i>
          <span>{{ busyKey === 'create' ? '保存中...' : '新增设置' }}</span>
        </button>
      </div>
    </section>

    <section class="settings-card expense-memory-list-card">
      <div class="card-head expense-memory-list-head">
        <div>
          <h4>当前设置与版本记录</h4>
          <p>更新会创建新版本，旧版本保留为可追溯记录。</p>
        </div>
        <button class="expense-memory-refresh-button" type="button" :disabled="loading" @click="loadPanel">
          <i :class="loading ? 'mdi mdi-loading mdi-spin' : 'mdi mdi-refresh'"></i>
          <span>刷新</span>
        </button>
      </div>

      <div v-if="loading" class="expense-memory-state" role="status">
        <i class="mdi mdi-loading mdi-spin"></i>
        <span>正在读取组织记忆...</span>
      </div>
      <div v-else-if="loadError" class="expense-memory-state is-error" role="alert">
        <i class="mdi mdi-alert-circle-outline"></i>
        <span>{{ loadError }}</span>
      </div>
      <div v-else-if="!memories.length" class="expense-memory-state">
        <i class="mdi mdi-brain"></i>
        <span>尚未配置企业或部门记忆。</span>
      </div>

      <div v-else class="expense-memory-list">
        <article v-for="memory in memories" :key="memory.id" class="expense-memory-item">
          <header>
            <div>
              <span class="expense-memory-scope-badge" :class="`is-${memory.scopeType}`">
                {{ memory.scopeType === 'enterprise' ? '企业' : '部门' }}
              </span>
              <strong>{{ memory.scopeLabel }}</strong>
            </div>
            <span class="expense-memory-status" :class="`is-${memory.status}`">
              {{ resolveStatusLabel(memory.status) }}
            </span>
          </header>

          <dl>
            <div><dt>出行基线</dt><dd>{{ memory.value || '未设置' }}</dd></div>
            <div><dt>版本</dt><dd>第 {{ memory.generation }} 版</dd></div>
            <div><dt>有效期</dt><dd>{{ formatDateTime(memory.expiresAt) }}</dd></div>
            <div><dt>维护来源</dt><dd>{{ memory.sourceLabel }}</dd></div>
          </dl>

          <div v-if="memory.status === 'active'" class="expense-memory-item-actions">
            <button type="button" @click="startEdit(memory)">更新版本</button>
            <button class="danger" type="button" @click="startRevoke(memory)">撤销</button>
          </div>

          <div v-if="editingId === memory.id" class="expense-memory-inline-editor">
            <EnterpriseSelect v-model="editForm.value" :options="transportOptions" />
            <input v-model.number="editForm.expiresInDays" type="number" min="30" max="365" aria-label="更新后有效天数" />
            <input v-model="editForm.reason" type="text" maxlength="255" placeholder="请填写更新理由" />
            <div>
              <button type="button" :disabled="busyKey === memory.id" @click="saveUpdate(memory)">保存新版本</button>
              <button type="button" @click="closeInlineActions">取消</button>
            </div>
          </div>

          <div v-if="revokingId === memory.id" class="expense-memory-inline-editor is-danger">
            <p>撤销后该作用域将停止自动填充，已生成的申请不受影响。</p>
            <input v-model="revokeReason" type="text" maxlength="255" placeholder="请填写撤销理由" />
            <div>
              <button class="danger" type="button" :disabled="busyKey === memory.id" @click="confirmRevoke(memory)">确认撤销</button>
              <button type="button" @click="closeInlineActions">取消</button>
            </div>
          </div>
        </article>
      </div>
    </section>
  </div>
</template>

<script setup>
import { onMounted, reactive, ref, watch } from 'vue'

import EnterpriseSelect from '../components/shared/EnterpriseSelect.vue'
import { useToast } from '../composables/useToast.js'
import { fetchEmployeeMeta } from '../services/employees.js'
import {
  EXPENSE_MEMORY_TRANSPORT_OPTIONS,
  createOrganizationExpenseMemory,
  fetchOrganizationExpenseMemories,
  revokeOrganizationExpenseMemory,
  updateOrganizationExpenseMemory
} from '../services/expenseApplicationMemories.js'

const { toast } = useToast()
const scopeOptions = [
  { value: 'enterprise', label: '企业统一', desc: '对当前租户内所有员工生效' },
  { value: 'department', label: '指定部门', desc: '仅对选定组织单元生效' }
]
const transportOptions = EXPENSE_MEMORY_TRANSPORT_OPTIONS.map((value) => ({ value, label: value }))
const memories = ref([])
const departmentOptions = ref([])
const loading = ref(false)
const loadError = ref('')
const busyKey = ref('')
const editingId = ref('')
const revokingId = ref('')
const revokeReason = ref('')
const revokeRequestId = ref('')
const createForm = reactive({
  scopeType: 'enterprise',
  scopeId: '',
  value: '火车',
  expiresInDays: 180,
  reason: '',
  requestId: ''
})
const editForm = reactive({ value: '火车', expiresInDays: 180, reason: '', requestId: '' })

function createRequestId(prefix) {
  const suffix = globalThis.crypto?.randomUUID?.()
    || `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`
  return `${prefix}:${suffix}`
}

watch(
  () => [
    createForm.scopeType,
    createForm.scopeId,
    createForm.value,
    createForm.expiresInDays,
    createForm.reason
  ],
  () => { createForm.requestId = '' }
)

watch(
  () => [editForm.value, editForm.expiresInDays, editForm.reason],
  () => { editForm.requestId = '' }
)

watch(revokeReason, () => { revokeRequestId.value = '' })

function normalizeDepartmentOptions(payload = {}) {
  const options = Array.isArray(payload?.organizationOptions) ? payload.organizationOptions : []
  return options
    .filter((item) => item?.id && item?.unitType === 'department')
    .map((item) => ({
      value: String(item.id),
      label: `${String(item.name || '未命名部门')}（${String(item.code || item.id)}）`
    }))
}

async function loadPanel() {
  loading.value = true
  loadError.value = ''
  const [memoryResult, employeeMetaResult] = await Promise.allSettled([
    fetchOrganizationExpenseMemories(),
    fetchEmployeeMeta()
  ])
  if (memoryResult.status === 'fulfilled') {
    memories.value = memoryResult.value
  } else {
    memories.value = []
    loadError.value = memoryResult.reason?.message || '组织记忆加载失败，请稍后重试。'
  }
  departmentOptions.value = employeeMetaResult.status === 'fulfilled'
    ? normalizeDepartmentOptions(employeeMetaResult.value)
    : []
  loading.value = false
}

async function refreshMemories() {
  memories.value = await fetchOrganizationExpenseMemories()
}

function selectScope(scopeType) {
  createForm.scopeType = scopeType
  if (scopeType === 'enterprise') createForm.scopeId = ''
}

async function createMemory() {
  busyKey.value = 'create'
  try {
    createForm.requestId ||= createRequestId('organization-memory-create')
    await createOrganizationExpenseMemory(createForm)
    createForm.reason = ''
    createForm.requestId = ''
    await refreshMemories()
    toast('组织记忆已保存。')
  } catch (error) {
    toast(error?.message || '组织记忆保存失败。')
  } finally {
    busyKey.value = ''
  }
}

function remainingDays(expiresAt) {
  const target = new Date(expiresAt).getTime()
  const days = Math.ceil((target - Date.now()) / 86400000)
  if (!Number.isFinite(days)) return 180
  return Math.max(30, Math.min(365, days))
}

function startEdit(memory) {
  editingId.value = memory.id
  revokingId.value = ''
  editForm.value = memory.value
  editForm.expiresInDays = remainingDays(memory.expiresAt)
  editForm.reason = ''
  editForm.requestId = ''
}

function startRevoke(memory) {
  revokingId.value = memory.id
  editingId.value = ''
  revokeReason.value = ''
  revokeRequestId.value = ''
  editForm.requestId = ''
}

function closeInlineActions() {
  editingId.value = ''
  revokingId.value = ''
  revokeReason.value = ''
  revokeRequestId.value = ''
}

async function saveUpdate(memory) {
  busyKey.value = memory.id
  try {
    editForm.requestId ||= createRequestId(`organization-memory-update:${memory.id}`)
    await updateOrganizationExpenseMemory(memory.id, {
      ...editForm,
      expectedGeneration: memory.generation
    })
    closeInlineActions()
    await refreshMemories()
    toast('组织记忆新版本已生效。')
  } catch (error) {
    toast(error?.message || '组织记忆更新失败。')
    await refreshMemories().catch(() => {})
  } finally {
    busyKey.value = ''
  }
}

async function confirmRevoke(memory) {
  busyKey.value = memory.id
  try {
    revokeRequestId.value ||= createRequestId(`organization-memory-revoke:${memory.id}`)
    await revokeOrganizationExpenseMemory(memory.id, {
      expectedGeneration: memory.generation,
      reason: revokeReason.value,
      requestId: revokeRequestId.value
    })
    closeInlineActions()
    await refreshMemories()
    toast('组织记忆已撤销。')
  } catch (error) {
    toast(error?.message || '组织记忆撤销失败。')
    await refreshMemories().catch(() => {})
  } finally {
    busyKey.value = ''
  }
}

function resolveStatusLabel(status) {
  return { active: '生效中', suppressed: '已被新版替换', revoked: '已撤销', expired: '已过期' }[status] || '已停用'
}

function formatDateTime(value) {
  const date = new Date(value)
  if (!value || Number.isNaN(date.getTime())) return '未设置'
  return new Intl.DateTimeFormat('zh-CN', { dateStyle: 'medium', timeStyle: 'short' }).format(date)
}

onMounted(loadPanel)
</script>

<style scoped src="../assets/styles/views/expense-memory-settings-panel.css"></style>
