<template>
  <div class="vm-crud-toolbar">
    <div class="vm-crud-toolbar__left">
      <template v-if="isDataI18nView">
        <vm-data-i18n-btn v-if="showDataI18n" :text="dataI18nText" />
        <vm-data-i18n-lang />
      </template>
      <template v-else>
        <button
          v-if="showAddBtn"
          type="button"
          class="vm-crud-toolbar__btn is-primary"
          @click="onAdd"
        >
          <i class="ri-add-line" />
          {{ addText ?? crudLabel('add', crud.dict.label) }}
        </button>
        <button
          v-if="showDeleteBtn"
          type="button"
          class="vm-crud-toolbar__btn is-danger"
          :disabled="!crud.selection.value.length"
          @click="crud.rowDelete()"
        >
          <i class="ri-delete-bin-line" />
          {{ deleteText ?? crudLabel('multiDelete', crud.dict.label) }}
        </button>
        <vm-export-btn
          v-if="showExport"
          :text="exportText || crudLabel('export', crud.dict.label)"
          :filename="exportFilename"
          :max-export-limit="maxExportLimit"
          :columns="exportColumns"
          :data="exportData"
        />
        <vm-import-btn
          v-if="showImport"
          :text="importText || crudLabel('import', crud.dict.label)"
          :tip="importTip"
          :template-filename="importTemplateFilename"
          :max-size-mb="importMaxSizeMb"
        />
        <slot />
      </template>
    </div>
    <div class="vm-crud-toolbar__right">
      <slot name="right" />
      <div v-if="showSearchActions" class="vm-crud-toolbar__search">
        <button type="button" class="vm-crud-toolbar__btn is-primary" @click="onSearch">
          {{ crudLabel('search', crud.dict.label) }}
        </button>
        <button type="button" class="vm-crud-toolbar__btn is-ghost" @click="onReset">
          {{ crudLabel('reset', crud.dict.label) }}
        </button>
      </div>
      <vm-tabs
        v-if="showViewTabs"
        :model-value="crud.trashMode.value"
        :items="viewTabs"
        @update:model-value="onViewTab"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { useVome } from '../hooks/useVome'
import { useCrud } from './useCrud'
import VmExportBtn from './vm-export-btn.vue'
import VmImportBtn from './vm-import-btn.vue'
import VmDataI18nBtn from './vm-data-i18n-btn.vue'
import VmDataI18nLang from './vm-data-i18n-lang.vue'
import VmTabs from './vm-tabs.vue'
import { canUseDataI18n } from './data-i18n'
import { crudLabel } from './style'
import type {
  CrudColumn,
  CrudTrashMode,
} from '../../../typings/admin/comm/crud'
defineOptions({ name: 'vm-toolbar' })

const props = withDefaults(
  defineProps<{
    /** 显示搜索/重置（默认开；放在列表/回收站左侧） */
    search?: boolean
    /** 显示导出（默认开；需 page/list 权限） */
    showExport?: boolean
    /** 显示导入（默认开；需 add 权限） */
    showImport?: boolean
    /** 显示业务数据翻译（默认开；EPS dataI18n 且在语言 Tab） */
    showDataI18n?: boolean
    dataI18nText?: string
    /**
     * 新增前置默认值（可选）：对象直接带入表单；函数 await 后带入。
     * 未传 / 空对象 → 仍正常打开新增。仅函数显式返回 `null` 时中止（前置校验未通过）。
     */
    addData?:
      | Record<string, unknown>
      | (() => Record<string, unknown> | null | Promise<Record<string, unknown> | null>)
    /** 回收站中是否隐藏新增（默认 true） */
    hideAddInTrash?: boolean
    addText?: string
    deleteText?: string
    exportText?: string
    exportFilename?: string | (() => string)
    maxExportLimit?: number
    exportColumns?: CrudColumn[]
    exportData?:
      | Record<string, unknown>[]
      | ((params: Record<string, unknown>) => Promise<Record<string, unknown>[]>)
    importText?: string
    importTip?: string
    importTemplateFilename?: string | (() => string)
    importMaxSizeMb?: number
  }>(),
  {
    search: true,
    showExport: true,
    showImport: true,
    showDataI18n: true,
    hideAddInTrash: true,
    maxExportLimit: 5000,
    importMaxSizeMb: 10,
  },
)

const crud = useCrud()
const { service } = useVome()

const dataI18nEnabled = computed(() => canUseDataI18n(crud.service, service).ok)

/** 有 restore 权限（Controller api + 权限码）才显示列表/回收站 */
const showTrash = computed(() => Boolean(crud.getPermission('restore')))

const showViewTabs = computed(() => showTrash.value || dataI18nEnabled.value)

const viewTabs = computed(() => {
  const tabs: Array<{ label: string; value: CrudTrashMode }> = [
    { label: crudLabel('list', crud.dict.label), value: 'default' },
  ]
  if (showTrash.value) {
    tabs.push({
      label: crudLabel('trash', crud.dict.label),
      value: 'onlyTrashed',
    })
  }
  if (dataI18nEnabled.value) {
    tabs.push({ label: crudLabel('dataI18n', crud.dict.label), value: 'dataI18n' })
  }
  return tabs
})

const isDataI18nView = computed(() => crud.trashMode.value === 'dataI18n')

/** 有 add 权限才显示；回收站内可再藏 */
const showAddBtn = computed(() => {
  if (!crud.getPermission('add')) return false
  if (props.hideAddInTrash && crud.trashMode.value === 'onlyTrashed') return false
  return true
})

/** 有 delete 权限才显示 */
const showDeleteBtn = computed(() => Boolean(crud.getPermission('delete')))

const showSearchActions = computed(
  () =>
    props.search &&
    crud.hasSearchFilters.value &&
    crud.trashMode.value !== 'dataI18n',
)

async function onAdd() {
  const raw = props.addData
  if (typeof raw === 'function') {
    const defaults = await raw()
    // 仅函数显式返回 null 表示前置未满足；undefined / 空对象仍打开
    if (defaults === null) return
    crud.rowAdd(defaults ?? {})
    return
  }
  crud.rowAdd(raw ?? {})
}

function onSearch() {
  crud.searchActions.value?.search()
}

function onReset() {
  crud.searchActions.value?.reset()
}

function onViewTab(mode: string | number) {
  const next = String(mode) as CrudTrashMode
  if (next !== 'default' && next !== 'onlyTrashed' && next !== 'dataI18n') return
  if (next === 'onlyTrashed' && !showTrash.value) return
  if (next === 'dataI18n' && !dataI18nEnabled.value) return
  crud.trashMode.value = next
  crud.pagination.value = { ...crud.pagination.value, page: 1 }
  // 语言 Tab：先清空旧列表，避免 rowKey 已切到 __rowKey 而行数据仍是业务行 → key=undefined
  if (next === 'dataI18n') {
    crud.list.value = []
    crud.selection.value = []
    return
  }
  void crud.refresh()
}
</script>

<style lang="scss" scoped>
.vm-crud-toolbar {
  display: flex;
  flex: 1;
  min-width: 0;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.vm-crud-toolbar__left {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.vm-crud-toolbar__right {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  margin-left: auto;
  gap: 10px;
}

.vm-crud-toolbar__search {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.vm-crud-toolbar__btn {
  display: inline-flex;
  height: 36px;
  align-items: center;
  gap: 4px;
  padding: 0 14px;
  border: none;
  border-radius: 12px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, opacity 0.15s ease;

  &:disabled {
    cursor: not-allowed;
    opacity: 0.45;
  }

  &.is-primary {
    background: var(--brand);
    color: #fff;

    &:hover:not(:disabled) {
      background: var(--brand-deep);
    }
  }

  &.is-ghost {
    background: var(--muted);
    color: var(--foreground);

    &:hover:not(:disabled) {
      background: color-mix(in srgb, var(--muted) 70%, var(--foreground) 8%);
    }
  }

  &.is-danger {
    background: var(--danger-soft);
    color: var(--danger);

    &:hover:not(:disabled) {
      background: color-mix(in srgb, var(--danger-soft) 70%, var(--danger) 12%);
    }
  }
}

/* 中窄屏（含侧栏半宽）：展平左右分区，统一流式换行；宽屏仍左右布局 */
@media (max-width: 1280px) {
  .vm-crud-toolbar,
  .vm-crud-toolbar__left,
  .vm-crud-toolbar__right,
  .vm-crud-toolbar__search {
    display: contents;
  }
}
</style>
