<script setup lang="ts">
/**
 * OA 场景 - 企业微信图文消息列表（news）
 *
 * 用于 work_wechat / work_wechat_app 平台 news 消息类型的 articles 字段编辑。
 * 每条 article 字段对齐企微官方结构（WorkWechatAppChannel::buildPayload case 'news'）：
 *   - title       标题（必填）
 *   - description 描述（必填）
 *   - url         点击跳转链接（必填）
 *   - picurl      封面图 URL（从素材库选；xk_file.type=0 即图片）
 *
 * 受 maxCount 限制（企微限制 1~8 条）。
 */
import { computed } from 'vue';

import { Button, Input, Textarea } from 'ant-design-vue';

import UploadImage from '#/components/form/components/upload-image.vue';

interface NewsArticle {
  title?: string;
  description?: string;
  url?: string;
  picurl?: string;
}

const props = withDefaults(
  defineProps<{
    /** 双向绑定的 articles 数组 */
    modelValue?: NewsArticle[];
    /** 最大条数（企微限制 8） */
    maxCount?: number;
  }>(),
  {
    modelValue: () => [],
    maxCount: 8,
  },
);

const emit = defineEmits<{
  'update:modelValue': [value: NewsArticle[]];
}>();

/** 内部可变副本（每次更新都重新生成新数组触发响应） */
const list = computed<NewsArticle[]>({
  get: () => Array.isArray(props.modelValue) ? props.modelValue : [],
  set: (val) => emit('update:modelValue', val),
});

/** 是否允许新增 */
const canAdd = computed(() => list.value.length < props.maxCount);

/** 更新指定下标 article 的字段 */
function updateItem(index: number, key: keyof NewsArticle, value: string) {
  const next = list.value.map((item, i) =>
    i === index ? { ...item, [key]: value } : item,
  );
  list.value = next;
}

/** 更新封面图 URL（UploadImage 返回 string[]） */
function updateImage(index: number, urls: string[]) {
  updateItem(index, 'picurl', urls[0] || '');
}

/** 新增一条空白 article */
function addItem() {
  if (!canAdd.value) return;
  list.value = [...list.value, {}];
}

/** 删除指定 article */
function removeItem(index: number) {
  list.value = list.value.filter((_, i) => i !== index);
}
</script>

<template>
  <div class="news-list">
    <div
      v-for="(item, idx) in list"
      :key="idx"
      class="news-item"
    >
      <div class="news-head">
        <span class="news-index">图文 {{ idx + 1 }}</span>
        <Button
          type="link"
          size="small"
          danger
          class="news-del"
          @click="removeItem(idx)"
        >
          删除
        </Button>
      </div>

      <div class="news-form">
        <div class="form-row">
          <label class="row-label">
            标题<span class="req">*</span>
          </label>
          <Input
            :value="item.title"
            placeholder="图文标题（必填）"
            size="small"
            allow-clear
            @update:value="(v: string) => updateItem(idx, 'title', v)"
          />
        </div>

        <div class="form-row">
          <label class="row-label">
            描述<span class="req">*</span>
          </label>
          <Textarea
            :value="item.description"
            placeholder="图文描述（必填）"
            :rows="2"
            size="small"
            @update:value="(v: string) => updateItem(idx, 'description', v)"
          />
        </div>

        <div class="form-row">
          <label class="row-label">
            跳转链接<span class="req">*</span>
          </label>
          <Input
            :value="item.url"
            placeholder="https://（必填）"
            size="small"
            allow-clear
            @update:value="(v: string) => updateItem(idx, 'url', v)"
          />
        </div>

        <div class="form-row">
          <label class="row-label">封面图</label>
          <UploadImage
            :model-value="item.picurl ? [item.picurl] : []"
            :multiple="false"
            :max-count="1"
            :accept-types="[0]"
            @update:model-value="(urls: string[]) => updateImage(idx, urls)"
          />
        </div>
      </div>
    </div>

    <Button
      v-if="canAdd"
      type="dashed"
      size="small"
      block
      @click="addItem"
    >
      + 添加图文（{{ list.length }}/{{ maxCount }}）
    </Button>
    <div v-else-if="list.length > 0" class="max-hint">
      已达上限 {{ maxCount }} 条
    </div>
  </div>
</template>

<style scoped lang="scss">
.news-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
}

.news-item {
  padding: 8px;
  border: 1px solid var(--ant-color-border-secondary, #e5e6eb);
  border-radius: 6px;
}

.news-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}

.news-index {
  font-size: 12px;
  font-weight: 600;
  color: var(--ant-color-text-secondary, #4e5969);
}

.news-del {
  padding: 0 4px;
  height: auto;
  font-size: 12px;
}

.news-form {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.form-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.row-label {
  font-size: 11px;
  color: var(--ant-color-text-secondary, #4e5969);
}

.req {
  margin-left: 2px;
  color: var(--ant-color-error, #f53f3f);
}

.max-hint {
  text-align: center;
  font-size: 11px;
  color: var(--ant-color-text-tertiary, #86909c);
}
</style>
