<script setup lang="ts">
import { ref } from 'vue';
import ElXMarkdown from 'vue-element-plus-x/es/XMarkdown/index.js';

import { EasyFlowFormModal } from '@easyflow/common-ui';
import { $t } from '@easyflow/locales';

import { Delete, EditPen, MoreFilled } from '@element-plus/icons-vue';
import {
  ElButton,
  ElDropdown,
  ElDropdownItem,
  ElDropdownMenu,
  ElForm,
  ElFormItem,
  ElIcon,
  ElInput,
  ElMessage,
  ElMessageBox,
  ElTable,
  ElTableColumn,
} from 'element-plus';

import { api } from '#/api/request';
import PageData from '#/components/page/PageData.vue';
import {
  markdownRenderProps,
  resolveMarkdownContent,
} from '#/views/ai/documentCollection/markdown-content';
import { buildKnowledgePath } from '#/views/ai/documentCollection/share-path';

const props = defineProps({
  documentId: {
    type: String,
    default: '',
  },
  manageable: {
    type: Boolean,
    default: true,
  },
  requestClient: {
    type: Object as any,
    default: () => api,
  },
  endpointPrefix: {
    type: String,
    default: '',
  },
});
const dialogVisible = ref(false);
const pageDataRef = ref();
const handleEdit = (row: any) => {
  if (!props.manageable) {
    ElMessage.warning($t('documentCollection.managePermissionHint'));
    return;
  }
  form.value = { id: row.id, content: row.content };
  openDialog();
};
const handleDelete = (row: any) => {
  if (!props.manageable) {
    ElMessage.warning($t('documentCollection.managePermissionHint'));
    return;
  }
  ElMessageBox.confirm($t('message.deleteAlert'), $t('message.noticeTitle'), {
    confirmButtonText: $t('message.ok'),
    cancelButtonText: $t('message.cancel'),
    type: 'warning',
  })
    .then(() => {
      btnLoading.value = true;
      props.requestClient
        .post(
          buildKnowledgePath(
            props.endpointPrefix,
            '/api/v1/documentChunk/removeChunk',
          ),
          { id: row.id },
        )
        .then((res: any) => {
          btnLoading.value = false;
          if (res.errorCode !== 0) {
            ElMessage.error(res.message);
            return;
          }
          ElMessage.success($t('message.deleteOkMessage'));
          pageDataRef.value.setQuery(queryParams);
        });
    })
    .catch(() => {});
};
const openDialog = () => {
  dialogVisible.value = true;
};
const closeDialog = () => {
  dialogVisible.value = false;
};
const queryParams = ref({
  documentId: props.documentId,
  sortKey: 'sorting',
  sortType: 'asc',
});
const save = () => {
  if (!props.manageable) {
    ElMessage.warning($t('documentCollection.managePermissionHint'));
    return;
  }
  btnLoading.value = true;
  props.requestClient
    .post(
      buildKnowledgePath(props.endpointPrefix, '/api/v1/documentChunk/update'),
      form.value,
    )
    .then((res: any) => {
      btnLoading.value = false;
      if (res.errorCode !== 0) {
        ElMessage.error(res.message);
        return;
      }
      ElMessage.success($t('message.updateOkMessage'));
      pageDataRef.value.setQuery(queryParams);
      closeDialog();
    });
};
const btnLoading = ref(false);
const basicFormRef = ref();
const form = ref({
  id: '',
  content: '',
});

const getChunkOptions = (row: any) => row?.options || {};

const getMarkdown = (row: any) =>
  resolveMarkdownContent(getChunkOptions(row)?.renderMarkdown || row?.content);

const isExcelChunk = (row: any) => {
  const options = getChunkOptions(row);
  const sourceFileExt = String(
    options?.sourceFileExt || options?.['splitter.sourceFileExt'] || '',
  ).toLowerCase();

  return Boolean(
    sourceFileExt === 'xlsx' ||
      options?.sheetName ||
      options?.rowStart ||
      options?.rowEnd,
  );
};

const shouldUseExcelChunkCards = (pageList: any[] = []) =>
  pageList.length > 0 && pageList.every((row) => isExcelChunk(row));

const getSheetName = (row: any) =>
  String(getChunkOptions(row)?.sheetName || '');

const getRowStart = (row: any) => {
  const rowStart = Number(getChunkOptions(row)?.rowStart || 0);
  return Math.max(rowStart, 0);
};

const getRowEnd = (row: any) => {
  const rowEnd = Number(getChunkOptions(row)?.rowEnd || 0);
  return Math.max(rowEnd, 0);
};

const getRowRangeLabel = (row: any) => {
  const rowStart = getRowStart(row);
  const rowEnd = getRowEnd(row);
  if (rowStart > 0 && rowEnd > 0) {
    return rowStart === rowEnd
      ? `第 ${rowStart} 行`
      : `第 ${rowStart}-${rowEnd} 行`;
  }
  if (rowStart > 0) {
    return `第 ${rowStart} 行起`;
  }
  return '';
};

const getChunkTitle = (row: any) => {
  const options = getChunkOptions(row);
  if (options?.sourceLabel) {
    return String(options.sourceLabel);
  }
  const sheetName = getSheetName(row);
  const rowRangeLabel = getRowRangeLabel(row);
  if (sheetName && rowRangeLabel) {
    return `${sheetName} · ${rowRangeLabel}`;
  }
  return sheetName || row?.id || '-';
};

const getChunkIndexLabel = (row: any) => {
  const sorting = Number(row?.sorting || 0);
  if (sorting <= 0) {
    return '';
  }
  return String(sorting).padStart(2, '0');
};

const getChunkHeaderLabel = (row: any) => {
  const chunkIndexLabel = getChunkIndexLabel(row);
  const chunkTitle = getChunkTitle(row);
  if (chunkIndexLabel) {
    return `分块 ${chunkIndexLabel} · ${chunkTitle}`;
  }
  return chunkTitle;
};
</script>

<template>
  <div>
    <PageData
      :page-url="
        buildKnowledgePath(props.endpointPrefix, '/api/v1/documentChunk/page')
      "
      ref="pageDataRef"
      :page-size="10"
      :request-client="props.requestClient"
      :extra-query-params="queryParams"
    >
      <template #default="{ pageList }">
        <div v-if="shouldUseExcelChunkCards(pageList)" class="chunk-board">
          <article v-for="row in pageList" :key="row.id" class="chunk-card">
            <div v-if="props.manageable" class="chunk-card__toolbar">
              <ElButton
                circle
                text
                type="primary"
                class="chunk-card__action"
                @click="handleEdit(row)"
              >
                <ElIcon><EditPen /></ElIcon>
              </ElButton>
              <ElDropdown>
                <ElButton
                  circle
                  text
                  class="chunk-card__action chunk-card__action--ghost"
                >
                  <ElIcon><MoreFilled /></ElIcon>
                </ElButton>

                <template #dropdown>
                  <ElDropdownMenu>
                    <ElDropdownItem @click="handleDelete(row)">
                      <ElButton link type="danger" :icon="Delete">
                        {{ $t('button.delete') }}
                      </ElButton>
                    </ElDropdownItem>
                  </ElDropdownMenu>
                </template>
              </ElDropdown>
            </div>

            <div class="chunk-card__header">
              <div class="chunk-card__eyebrow">
                <span class="chunk-card__eyebrow-dot"></span>
                <span>{{ getChunkHeaderLabel(row) }}</span>
              </div>
            </div>

            <div v-if="getMarkdown(row)" class="chunk-card__content">
              <div class="chunk-rich-content chunk-rich-content--card">
                <ElXMarkdown
                  :markdown="getMarkdown(row)"
                  :allow-html="markdownRenderProps.allowHtml"
                  :sanitize="markdownRenderProps.sanitize"
                />
              </div>
            </div>
            <span v-else class="chunk-table__empty">-</span>
          </article>
        </div>

        <ElTable v-else :data="pageList" style="width: 100%" size="large">
          <ElTableColumn
            prop="content"
            :label="$t('documentCollection.content')"
            min-width="240"
          >
            <template #default="{ row }">
              <div v-if="getMarkdown(row)" class="chunk-rich-content">
                <ElXMarkdown
                  :markdown="getMarkdown(row)"
                  :allow-html="markdownRenderProps.allowHtml"
                  :sanitize="markdownRenderProps.sanitize"
                />
              </div>
              <span v-else class="chunk-table__empty">-</span>
            </template>
          </ElTableColumn>
          <ElTableColumn
            v-if="props.manageable"
            :label="$t('common.handle')"
            width="100"
            align="right"
          >
            <template #default="{ row }">
              <div class="flex items-center gap-3">
                <ElButton link type="primary" @click="handleEdit(row)">
                  {{ $t('button.edit') }}
                </ElButton>

                <ElDropdown>
                  <ElButton link :icon="MoreFilled" />

                  <template #dropdown>
                    <ElDropdownMenu>
                      <ElDropdownItem @click="handleDelete(row)">
                        <ElButton link type="danger" :icon="Delete">
                          {{ $t('button.delete') }}
                        </ElButton>
                      </ElDropdownItem>
                    </ElDropdownMenu>
                  </template>
                </ElDropdown>
              </div>
            </template>
          </ElTableColumn>
        </ElTable>
      </template>
    </PageData>
    <EasyFlowFormModal
      v-if="props.manageable"
      v-model:open="dialogVisible"
      :closable="!btnLoading"
      :title="$t('button.edit')"
      width="50%"
      :confirm-loading="btnLoading"
      :confirm-text="$t('button.save')"
      :submitting="btnLoading"
      @confirm="save"
    >
      <ElForm
        ref="basicFormRef"
        :model="form"
        label-position="top"
        class="easyflow-modal-form easyflow-modal-form--compact"
      >
        <ElFormItem>
          <ElInput v-model="form.content" :rows="20" type="textarea" />
        </ElFormItem>
      </ElForm>
    </EasyFlowFormModal>
  </div>
</template>

<style scoped>
.chunk-board {
  display: grid;
  gap: 14px;
}

.chunk-card {
  position: relative;
  padding: 20px 20px 18px;
  overflow: hidden;
  background: var(--el-fill-color-blank);
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--el-color-primary-light-9) 80%, white) 0%,
    var(--el-fill-color-blank) 38%
  );
  border: 1px solid var(--el-border-color-light);
  border: 1px solid color-mix(in srgb, var(--el-border-color-light) 78%, white);
  border-radius: 18px;
  box-shadow: 0 18px 40px rgb(15 23 42 / 6%);
}

.chunk-card::before {
  position: absolute;
  inset: 0 auto 0 0;
  width: 4px;
  content: '';
  background: var(--el-color-primary);
  background: linear-gradient(
    180deg,
    var(--el-color-primary),
    color-mix(in srgb, var(--el-color-primary) 44%, white)
  );
}

.chunk-card__toolbar {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 1;
  display: flex;
  gap: 6px;
  align-items: center;
}

.chunk-card__action {
  width: 34px;
  height: 34px;
  color: var(--el-color-primary);
  background: var(--el-color-primary-light-9);
  background: color-mix(in srgb, var(--el-color-primary-light-9) 66%, white);
  border: 1px solid var(--el-color-primary-light-8);
  border: 1px solid
    color-mix(in srgb, var(--el-color-primary-light-8) 72%, white);
  box-shadow: 0 8px 18px rgb(37 99 235 / 10%);
}

.chunk-card__action--ghost {
  color: var(--el-text-color-secondary);
  background: rgb(255 255 255 / 86%);
  border-color: var(--el-border-color-light);
  border-color: color-mix(in srgb, var(--el-border-color-light) 86%, white);
  box-shadow: none;
}

.chunk-card__header {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding-right: 92px;
}

.chunk-card__eyebrow {
  display: inline-flex;
  gap: 8px;
  align-items: center;
  min-height: 28px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
  color: var(--el-text-color-secondary);
}

.chunk-card__eyebrow-dot {
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--el-color-primary);
  box-shadow: 0 0 0 4px var(--el-color-primary-light-9);
  box-shadow: 0 0 0 4px
    color-mix(in srgb, var(--el-color-primary-light-8) 50%, transparent);
}

.chunk-card__content {
  padding-top: 14px;
}

.chunk-rich-content {
  min-width: 0;
  padding: 4px 0;
  font-size: 14px;
  line-height: 1.72;
  color: var(--el-text-color-regular);
}

.chunk-rich-content--card {
  padding: 14px 16px;
  overflow-x: auto;
  background: rgb(255 255 255 / 82%);
  border: 1px solid rgb(15 23 42 / 6%);
  border-radius: 16px;
}

.chunk-rich-content :deep(.markdown-body) {
  font-size: inherit;
  line-height: inherit;
  color: inherit;
  background: transparent;
}

.chunk-rich-content :deep(.markdown-body > :first-child) {
  margin-top: 0;
}

.chunk-rich-content :deep(.markdown-body > :last-child) {
  margin-bottom: 0;
}

.chunk-rich-content :deep(*) {
  overflow-wrap: anywhere;
}

.chunk-rich-content :deep(p) {
  margin: 0 0 10px;
}

.chunk-rich-content :deep(p:last-child) {
  margin-bottom: 0;
}

.chunk-rich-content :deep(h1),
.chunk-rich-content :deep(h2),
.chunk-rich-content :deep(h3),
.chunk-rich-content :deep(h4),
.chunk-rich-content :deep(h5),
.chunk-rich-content :deep(h6) {
  margin: 14px 0 10px;
  font-weight: 600;
  line-height: 1.45;
  color: var(--el-text-color-primary);
}

.chunk-rich-content :deep(h1:first-child),
.chunk-rich-content :deep(h2:first-child),
.chunk-rich-content :deep(h3:first-child),
.chunk-rich-content :deep(h4:first-child),
.chunk-rich-content :deep(h5:first-child),
.chunk-rich-content :deep(h6:first-child) {
  margin-top: 0;
}

.chunk-rich-content :deep(ul),
.chunk-rich-content :deep(ol) {
  padding-left: 20px;
  margin: 0 0 12px;
}

.chunk-rich-content :deep(li + li) {
  margin-top: 4px;
}

.chunk-rich-content :deep(a) {
  color: var(--el-color-primary);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.chunk-rich-content :deep(img) {
  display: block;
  max-width: min(100%, 560px);
  height: auto;
  margin: 12px 0;
  border: 1px solid rgb(15 23 42 / 8%);
  border-radius: 12px;
  box-shadow: 0 10px 24px rgb(15 23 42 / 8%);
}

.chunk-rich-content :deep(table) {
  width: 100%;
  margin: 12px 0;
  overflow: hidden;
  border-collapse: collapse;
  background: rgb(255 255 255 / 92%);
  border: 1px solid rgb(15 23 42 / 8%);
  border-radius: 12px;
}

.chunk-rich-content :deep(th),
.chunk-rich-content :deep(td) {
  padding: 10px 12px;
  text-align: left;
  vertical-align: top;
  border: 1px solid rgb(15 23 42 / 8%);
}

.chunk-rich-content :deep(th) {
  font-weight: 600;
  color: var(--el-text-color-primary);
  background: rgb(37 99 235 / 4%);
}

.chunk-rich-content :deep(pre) {
  max-width: 100%;
  padding: 12px 14px;
  overflow: auto;
  background: rgb(15 23 42 / 4%);
  border: 1px solid rgb(15 23 42 / 6%);
  border-radius: 12px;
}

.chunk-rich-content :deep(blockquote) {
  padding-left: 12px;
  margin: 12px 0;
  color: var(--el-text-color-secondary);
  border-left: 3px solid rgb(37 99 235 / 24%);
}

.chunk-table__empty {
  color: var(--el-text-color-placeholder);
}

@media (max-width: 960px) {
  .chunk-card {
    padding: 18px 16px 16px;
  }

  .chunk-card__toolbar {
    position: static;
    justify-content: flex-end;
    padding-bottom: 12px;
  }

  .chunk-card__header {
    padding-right: 0;
  }

  .chunk-rich-content--card {
    padding: 12px;
  }

  .chunk-card__eyebrow {
    font-size: 12px;
  }
}

@supports not (color: color-mix(in srgb, red, blue)) {
  .chunk-card {
    border-color: var(--el-border-color-light);
  }

  .chunk-card__action {
    border-color: var(--el-color-primary-light-8);
  }

  .chunk-card__action--ghost {
    border-color: var(--el-border-color-light);
  }
}
</style>
