<script generic="F extends object,TT extends DefaultRow" lang="ts" setup>
import { elIcons } from '@/common/element/element.ts'
import APage from '@/components/a-page/APage.vue'
import Utils, { type ResetAble } from '@/common/utils'
import Colls from '@/common/utils/colls.ts'
import Strings from '@/common/utils/strings.ts'
import { saveFile } from '@/common/app'
import type { R } from '@/common/utils/http-util.ts'
import type {
  TableColumnCtx,
  TableInstance,
} from 'element-plus'
import type { DefaultRow } from 'element-plus/es/components/table/src/table/defaults'
import type {
  ActionColumnType,
  FormPropsType,
  TableActionType,
  TablePropsType,
  ToolType,
} from '@/components/page/a-page-type.ts'

const props = withDefaults(
  defineProps<{
    defaultSearchForm?: F
    paging?: (param: F) => Promise<R<G.PageResult<TT>>>
    list?: (param: F) => Promise<R<TT[]>>
    actionColumn?: ActionColumnType<TT>
    leftTools?: ToolType[]
    rightTools?: Required<Omit<ToolType, 'type' | 'label'>>[]
    tableProps?: TablePropsType<TT, F>
    searchFormProps?: FormPropsType
    exportHandler?: (param: F) => Promise<R<{ content: Blob, filename: string }>>
    simpleSearchFormProps?: FormPropsType
    formStyle?: {
      border: boolean
      colCount?: number
      vgap?: string
      hgap?: string
    }
  }>(),
  {
    tableProps: {
      // @ts-ignore
      rowKey: 'id',
      emptyText: '暂无数据',
    },
    // @ts-ignore
    searchFormProps: {
      labelPosition: 'left',
      labelWidth: '90px',
      inline: true,
    } as FormPropsType,
    // @ts-ignore
    simpleSearchFormProps: {
      labelWidth: '90px',
      labelPosition: 'left',
      inline: true,
    } as FormPropsType,
    formStyle: {
      // @ts-ignore
      border: false,
      colCount: 4,
      vgap: '20px',
      hgap: '20px',
    },
  },
)
const searchForm = Utils.resetAble(reactive<F>({
  ...(props.defaultSearchForm ?? {}),
  current: 1,
  size: 20,
} as F)) as ResetAble<F>
const tableData = Utils.resetAble(reactive<TT[]>([])) as ResetAble<TT[]>
const totalCount = ref(0)
const loading = ref<boolean>(false)
const showSearchForm = ref<boolean>(false)
const dataTableIns = useTemplateRef<TableInstance>('dataTable')

function doReset() {
  searchForm.$reset()
  doSearch()
}

function doSearch() {
  loading.value = true
  if (props.paging != null) {
    props.paging(searchForm.$clone() as F)
      .then((res) => {
        totalCount.value = res.data?.total ?? 0
        const records = res.data?.records ?? ([] as TT[])
        tableData.$reset(records)
      })
      .finally(() => {
        loading.value = false
      })
    return
  }
  if (props.list != null) {
    props.list(searchForm.$clone() as F)
      .then((res) => {
        totalCount.value = res.data?.length ?? 0
        const records = res.data ?? ([] as TT[])
        tableData.$reset(records)
      })
      .finally(() => {
        loading.value = false
      })
    return
  }
}

function doExport() {
  if (props.exportHandler == null) {
    return
  }
  loading.value = true
  saveFile(props.exportHandler(searchForm.$clone() as F))
    .finally(() => {
      loading.value = false
    })
}

function showSearchFormHandle() {
  showSearchForm.value = !showSearchForm.value
  searchForm.$reset()
}

function rowAction(data: { row: TT, column: TableColumnCtx, $index: number }, action: TableActionType<TT>) {
  if (action.loading != null) {
    action.loading = true
  }
  const result = action.action(data)
  if (result instanceof Promise) {
    result
      .then(reload => {
        if (reload) {
          doSearch()
        }
      })
      .finally(() => {
        if (action.loading != null) {
          action.loading = false
        }
      })
  }
}

defineExpose({
  doSearch,
  dataTableIns,
})
onMounted(doSearch)
</script>

<template>
  <APage class="form-page">
    <div v-show="showSearchForm" class="search-form">
      <ElScrollbar>
        <ElForm :class="{'border-form':formStyle.border}" v-bind="searchFormProps" @submit.prevent="doSearch">
          <slot :searchForm="searchForm" name="searchFormItem"/>
          <!-- <ElFormItem class="form-action-btn">
            <ElButton :icon="elIcons.Search" :loading="loading" native-type="submit" type="primary">搜索</ElButton>
            <ElButton :icon="elIcons.Refresh" :loading="loading" @click="doReset">重置</ElButton>
          </ElFormItem> -->
          <button style="display: none" type="submit"></button>
        </ElForm>
      </ElScrollbar>
    </div>
    <div class="data-list">
      <div class="tool-bar">
        <div class="tool-bar-left">
          <template v-if="!Colls.isEmpty(leftTools)">
            <ElButton v-for="(tool,i) in leftTools" :key="'tool-bar-left-'+i"
              :icon="Strings.isBlank(tool.icon)?undefined:elIcons[tool.icon!]"
              :type="tool.type ?? 'primary'"
              @click="tool.action">
              {{ tool.label }}
            </ElButton>
          </template>
        </div>
        <div class="tool-bar-right">
          <ElForm v-bind="simpleSearchFormProps" @submit.prevent="doSearch">
            <slot :searchForm="searchForm" name="simpleSearchFormItem"/>
            <button style="display: none" type="submit"></button>
          </ElForm>
          <ElTooltip content="搜索" placement="top">
            <ElDropdown split-button @click="doSearch" @command="(command: string)=>{
              if(command === 'reset'){
                doReset()
              }
            }">
              <ElButton :icon="elIcons.Search" :loading="loading" type="default"/>
              <template #dropdown>
                <ElDropdownMenu slot="dropdown">
                  <ElDropdownItem :icon="elIcons.Refresh" command="reset">重置并刷新</ElDropdownItem>
                </ElDropdownMenu>
              </template>
            </ElDropdown>
          </ElTooltip>
          <template v-if="!Colls.isEmpty(rightTools)">
            <ElButton v-for="(tool,i) in rightTools" :key="'tool-bar-right-'+i"
              :icon="elIcons[tool.icon]"
              @click="tool.action"/>
          </template>
          <ElTooltip v-if="exportHandler != null" content="导出" placement="top">
            <ElButton :icon="elIcons.Download" :loading="loading" type="default" @click="doExport"/>
          </ElTooltip>
          <ElTooltip :content="showSearchForm?'关闭高级搜索':'打开高级搜索'" placement="top">
            <ElButton :class="{'filter-btn-active':showSearchForm} " :icon="elIcons.Filter" type="default" @click="showSearchFormHandle"/>
          </ElTooltip>
        </div>
      </div>
      <ElTable
        v-loading="loading"
        :data="tableData"
        :empty-text="tableProps.emptyText?? '暂无数据'"
        :row-key="tableProps.rowKey?? 'id'"
        ref="dataTable"
        :lazy="tableProps.treeLoad ==null?undefined:true"
        :load="tableProps.treeLoad?((row, expanded, resolve)=>tableProps.treeLoad!(searchForm as F, row, expanded, resolve)):undefined"
        @expand-change="tableProps.treeLoad?((row:any, expandedRows:any)=>tableProps.treeLoad!(searchForm as F, row, expandedRows, undefined)):undefined"
        cell-class-name="table-cell"
        class="table-list"
        header-row-class-name="table-header"
        v-bind="tableProps"
      >
        <slot name="columns"/>
        <ElTableColumn v-if="!Colls.isEmpty(actionColumn?.tableActions)" :width="actionColumn?.width?? '180'" fixed="right" label="操作">
          <template #default="scope">
            <div class="action-btn">
              <template v-for="(tableAction,i) in actionColumn!.tableActions.filter(it=>(it.show==null?true:it.show(scope)))" :key="'action-btn-'+i">
                <ElPopconfirm
                  v-if="tableAction.confirm != null"
                  :cancel-button-text="tableAction.confirm.cancelButtonText?? '否'"
                  :confirm-button-text="tableAction.confirm.confirmButtonText?? '是'"
                  :title="typeof tableAction.confirm.title === 'function'?tableAction.confirm.title(scope):tableAction.confirm.title"
                  :width="tableAction.confirm.width?? '180'"
                  cancel-button-type="primary"
                  confirm-button-type="danger" placement="top" @confirm="rowAction(scope, tableAction)"
                >
                  <template #reference>
                    <template v-if="tableAction.tooltip==null || (Strings.isBlank(typeof tableAction.tooltip === 'function'?tableAction.tooltip(scope):tableAction.tooltip))">
                      <ElButton
                        v-if="tableAction.textBtn"
                        :icon="tableAction.icon==null?undefined:elIcons[tableAction.icon]"
                        :loading="tableAction.loading"
                        :type="tableAction.type"
                        class="text-btn"
                        text>
                        {{ tableAction.label }}
                      </ElButton>
                      <ElButton
                        v-else
                        :icon="tableAction.icon==null?undefined:elIcons[tableAction.icon]"
                        :loading="tableAction.loading"
                        :type="tableAction.type"
                        class="icon-btn"/>
                    </template>
                    <div v-else>
                      <ElTooltip :content="typeof tableAction.tooltip === 'function'?tableAction.tooltip(scope):tableAction.tooltip" placement="top">
                        <ElButton
                          v-if="tableAction.textBtn"
                          :icon="tableAction.icon==null?undefined:elIcons[tableAction.icon]"
                          :loading="tableAction.loading"
                          :type="tableAction.type"
                          class="text-btn"
                          text>
                          {{ tableAction.label }}
                        </ElButton>
                        <ElButton
                          v-else
                          :icon="tableAction.icon==null?undefined:elIcons[tableAction.icon]"
                          :loading="tableAction.loading"
                          :type="tableAction.type"
                          class="icon-btn"/>
                      </ElTooltip>
                    </div>
                  </template>
                </ElPopconfirm>
                <template v-else>
                  <template v-if="tableAction.tooltip==null || (Strings.isBlank(typeof tableAction.tooltip === 'function'?tableAction.tooltip(scope):tableAction.tooltip))">
                    <ElButton
                      v-if="tableAction.textBtn"
                      :icon="tableAction.icon==null?undefined:elIcons[tableAction.icon]"
                      :loading="tableAction.loading"
                      :type="tableAction.type"
                      class="text-btn"
                      text
                      @click="rowAction(scope, tableAction)">{{ tableAction.label }}
                    </ElButton>
                    <ElButton
                      v-else
                      :icon="tableAction.icon==null?undefined:elIcons[tableAction.icon]"
                      :loading="tableAction.loading"
                      :type="tableAction.type"
                      class="icon-btn"
                      @click="rowAction(scope, tableAction)"/>
                  </template>
                  <ElTooltip v-else :content="typeof tableAction.tooltip === 'function'?tableAction.tooltip(scope):tableAction.tooltip" placement="top">
                    <ElButton
                      v-if="tableAction.textBtn"
                      :icon="tableAction.icon==null?undefined:elIcons[tableAction.icon]"
                      :loading="tableAction.loading"
                      :type="tableAction.type"
                      class="text-btn"
                      text
                      @click="rowAction(scope, tableAction)">{{ tableAction.label }}
                    </ElButton>
                    <ElButton
                      v-else
                      :icon="tableAction.icon==null?undefined:elIcons[tableAction.icon]"
                      :loading="tableAction.loading"
                      :type="tableAction.type"
                      class="icon-btn"
                      @click="rowAction(scope, tableAction)"/>
                  </ElTooltip>
                </template>
              </template>
            </div>
          </template>
        </ElTableColumn>
      </ElTable>
      <ElPagination
        v-if="paging!=null"
        class="pagination"
        v-model:current-page="(searchForm as  G.PageParam).current"
        v-model:page-size="(searchForm as  G.PageParam).size"
        :hide-on-single-page="false"
        :page-sizes="[10, 20, 50, 100, 500]"
        :teleported="false"
        :total="totalCount"
        background
        layout="total, prev, pager, next, sizes, jumper"
        @change="doSearch"/>
    </div>
    <slot/>
  </APage>
</template>

<style lang="stylus" scoped>
.form-page {
  .search-form {
    border: 1px solid var(--el-border-color-light);
    padding: 20px;
    border-radius: 8px;
    background-color: white;
    //background-color: #FAFBFC;
    //box-shadow: rgba(0, 0, 0, 0.12) 0px 0px 12px 0px;
    max-height 242px

    & > div {
      max-height 168px
      width 100%;
    }

    .border-form {
      :deep(.el-form-item) {
        &:not(.form-action-btn) {
          background-color white
          border-radius: var(--el-input-border-radius, var(--el-border-radius-base));
          box-shadow: 0 0 0 1px var(--el-input-border-color, var(--el-border-color));
          padding: 1px;

          .el-form-item__label {
            border-right 1px solid #DCDFE6
            padding 1px 11px
          }

          .el-form-item__content {
            .el-input {
              .el-input__wrapper {
                border-radius unset
                box-shadow unset
              }
            }

            .el-select {
              .el-select__wrapper {
                border-radius unset
                box-shadow unset
              }
            }
          }
        }

      }
    }

    :deep(.el-form) {
      display grid
      grid-template-columns repeat(v-bind('formStyle.colCount'), 1fr)
      grid-auto-flow: dense;
      column-gap v-bind('formStyle.hgap');
      row-gap v-bind('formStyle.vgap');
      padding 5px

      .el-form-item {
        margin 0
      }

      .el-form-item.form-action-btn {
        grid-column: 1 / -1;

        .el-form-item__content {
          justify-content end
        }
      }
    }
  }

  .data-list {
    flex 1
    display flex
    flex-direction column
    border: 1px solid var(--el-border-color-light);
    padding: 15px 20px 20px 15px;
    border-radius: 8px;
    background-color: white;
    gap 20px
    //box-shadow: rgba(0, 0, 0, 0.12) 0px 0px 12px 0px;
    min-height: calc(100% - 225px);
    box-sizing: border-box;

    .tool-bar {
      display flex
      justify-content space-between
      //box-shadow: rgba(0, 0, 0, 0.12) 0px 0px 12px 0px;
      //padding 10px

      .tool-bar-left {
        flex 1
      }

      .tool-bar-right {
        flex 1
        display flex
        gap 10px
        justify-content end


        :deep(.el-form) {
          display flex
          gap 10px
          flex-shrink 0

          .el-form-item {
            margin: 0;
            flex 1
          }
        }

        :deep(.el-button--default) {
          width 32px
          color #4D5875
          background-color #F1F4F4
          border-color #F1F4F4
          margin 0

          &:hover {
            color var(--el-color-primary)
            background-color #E6EAEB;
            border-color #E6EAEB;
          }
        }


        :deep(.el-dropdown) {
          flex-shrink 0
        }

        :deep(.el-button--default).filter-btn-active {
          color var(--el-color-primary)
        }
      }
    }

    .table-list {
      flex 1;
      width 100%
      //box-shadow: rgba(0, 0, 0, 0.12) 0px 0px 12px 0px;
      //padding 10px

      :deep(.table-header) {
        color #454C59

        th {
          background-color #EDF1F7
          font-weight 500
          position relative

          & > div {
            display flex
            gap 5px
            align-items center
          }

          &:not(:first-child) > div::before {
            position: absolute;
            top: 50%;
            left: 1px;
            width: 1px;
            background-color: #D3D7DE;
            transform: translateY(-50%);
            content: "";
            height 50%
          }
        }
      }

      :deep(.table-cell) {
        color #2F3540
      }

      .action-btn {
        width 100%
        display flex
        flex-wrap wrap
        gap: 10px;

        .text-btn {
          margin 0
        }

        .icon-btn {
          margin 0
          padding: 8px;
          justify-content: center;
          align-items: center;
          //#ebf0ff
        }

        :deep(.el-button--default).icon-btn {
          color oklch(72% .19 231.6)
          background-color oklch(0.96 0.03 224.26)
          border-color oklch(0.96 0.03 224.26)
        }

        :deep(.el-button--danger).icon-btn {
          color oklch(73% .15 25.3)
          background-color oklch(0.96 0.02 22.09)
          border-color oklch(0.96 0.02 22.09)
        }
      }
    }

    .pagination {
      justify-content center

      :deep(.btn-next),
      :deep(.btn-prev),
      :deep(.el-pager) li {
        border-radius: 6px !important;
      }
    }
  }
}

@media (max-width: 900px) {
  .tool-bar {
    flex-direction column
    align-items start
    gap 10px
    justify-content space-between

    .tool-bar-right {
      width 100%
      justify-content space-between !important
    }
  }
}
</style>
