<template>
  <div class="container">
    <section class="hero fade-up">
      <div class="hero-badge">BATCH SCAN</div>
      <h1 class="hero-title">批量文本筛查</h1>
      <p class="hero-sub">上传 TXT 文件或手动输入，每行一条文本，系统自动逐行检测。</p>
    </section>

    <section class="card fade-up fade-up-delay-1">
      <div class="card-title">上传文件</div>
      <div class="card-desc">支持 TXT 文本文件，每行一条待检测内容。</div>
      <div class="btn-row">
        <label class="btn btn-primary" style="position: relative;">
          选择 TXT 文件
          <input
            type="file"
            accept=".txt,text/plain"
            style="position: absolute; inset: 0; opacity: 0; cursor: pointer;"
            @change="onChooseFile"
          />
        </label>
      </div>

      <div class="field" v-if="fileName">
        <div class="row">
          <span class="label">已选文件</span>
          <span class="value">{{ fileName }}</span>
        </div>
        <div class="row">
          <span class="label">文本条数</span>
          <span class="value">{{ lineCount }} 条</span>
        </div>
      </div>
    </section>

    <section class="card fade-up fade-up-delay-1">
      <div class="card-title">手动输入</div>
      <div class="card-desc">或直接粘贴文本内容，每行一条。</div>
      <textarea
        class="textarea"
        v-model="inputText"
        rows="8"
        placeholder="示例：&#10;点击链接领取红包&#10;今天下午三点开会"
      ></textarea>

      <div class="btn-row">
        <button class="btn btn-ghost" @click="fillDemo">填充示例</button>
        <button class="btn btn-accent" :disabled="loading" @click="submit">
          {{ loading ? '识别中...' : '开始识别' }}
        </button>
      </div>
    </section>

    <section class="card fade-up fade-up-delay-2" v-if="summary">
      <div class="card-title">识别汇总</div>
      <div class="grid-3">
        <div class="kpi">
          <div class="kpi-value">{{ summary.total }}</div>
          <div class="kpi-label">总条数</div>
        </div>
        <div class="kpi">
          <div class="kpi-value">{{ summary.spam_count }}</div>
          <div class="kpi-label">垃圾信息</div>
        </div>
        <div class="kpi">
          <div class="kpi-value">{{ summary.ham_count }}</div>
          <div class="kpi-label">正常信息</div>
        </div>
      </div>

      <div class="field">
        <div class="row">
          <span class="label">垃圾占比</span>
          <span class="value">{{ summary.spam_ratio_text }}</span>
        </div>
        <div class="progress-track">
          <div class="progress-fill" :style="{ width: summary.spam_ratio_text }"></div>
        </div>
      </div>

      <div class="field">
        <div class="row">
          <span class="label">拦截占比</span>
          <span class="value">{{ summary.blocked_ratio_text }}</span>
        </div>
        <div class="progress-track">
          <div class="progress-fill-safe" :style="{ width: summary.blocked_ratio_text }"></div>
        </div>
      </div>
    </section>

    <section class="card fade-up fade-up-delay-3" v-if="items.length">
      <div class="card-title">明细结果</div>
      <div class="btn-row" style="margin-bottom: 12px;">
        <button class="btn btn-ghost" :disabled="exporting" @click="exportXLSX">
          {{ exporting ? '导出中...' : '导出 Excel 文件' }}
        </button>
        <button class="btn btn-ghost" @click="copyCSV">复制 CSV 内容</button>
      </div>

      <div class="list-item" v-for="(item, idx) in items" :key="idx">
        <div class="item-title">{{ item.text }}</div>
        <div class="row">
          <span class="label">判定结果</span>
          <span :class="item.prediction === 'spam' ? 'status-spam' : 'status-ham'">{{ item.prediction_text }}</span>
        </div>
        <div class="row" v-if="item.category_label">
          <span class="label">分类标签</span>
          <span class="status-spam">{{ item.category_label }}</span>
        </div>
        <div class="row">
          <span class="label">置信度</span>
          <span class="value">{{ item.confidence_text }}</span>
        </div>
        <div class="progress-track">
          <div
            :class="item.prediction === 'spam' ? 'progress-fill' : 'progress-fill-safe'"
            :style="{ width: item.confidence_text }"
          ></div>
        </div>
        <div class="field" v-if="item.reason_tokens && item.reason_tokens.length">
          <span class="field-label">风险关键词</span>
          <div class="chip-group">
            <span
              v-for="(tk, i) in item.reason_tokens"
              :key="i"
              class="tag tag-danger"
              @click="showTokenWeight(tk)"
            >{{ tk.token }}</span>
          </div>
        </div>
      </div>
    </section>
  </div>
</template>

<script>
import { request } from '@/utils/request'
import { toast, confirm } from '@/utils/feedback'

export default {
  name: 'BatchView',
  data() {
    return {
      inputText: '',
      fileName: '',
      lineCount: 0,
      loading: false,
      exporting: false,
      summary: null,
      items: []
    }
  },
  methods: {
    formatPercent(value, digits = 2) {
      return `${(Number(value || 0) * 100).toFixed(digits)}%`
    },
    parseLines() {
      return (this.inputText || '')
        .split('\n')
        .map((line) => line.trim())
        .filter((line) => line.length >= 2)
    },
    onChooseFile(e) {
      const file = (e.target.files || [])[0]
      if (!file) return
      const reader = new FileReader()
      reader.onload = () => {
        const content = String(reader.result || '')
        const lines = content
          .split('\n')
          .map((line) => line.trim())
          .filter((line) => line.length >= 2)
        this.inputText = lines.join('\n')
        this.fileName = file.name
        this.lineCount = lines.length
        toast(`已读取 ${lines.length} 条文本`, 'success')
      }
      reader.onerror = () => toast('文件读取失败', 'error')
      reader.readAsText(file, 'utf-8')
      e.target.value = ''
    },
    async submit() {
      if (this.loading) return
      const items = this.parseLines()
      if (!items.length) {
        toast('请至少输入一条有效文本', 'error')
        return
      }
      this.loading = true
      try {
        const data = await request({ url: '/spam/predict/batch', method: 'POST', data: { items } })
        const sum = data.summary || {}
        this.summary = {
          ...sum,
          spam_ratio_text: this.formatPercent(sum.spam_ratio, 2),
          blocked_ratio_text: this.formatPercent(sum.blocked_ratio, 2)
        }
        this.items = (data.items || []).map((item) => ({
          ...item,
          confidence_text: this.formatPercent(item.confidence, 2)
        }))
      } finally {
        this.loading = false
      }
    },
    fillDemo() {
      this.inputText = [
        '点击链接领取购物补贴，名额有限。',
        '明天下午三点上线前演练。',
        '高薪兼职日结，扫码进群。',
        '测试报告我已经同步到项目群。'
      ].join('\n')
    },
    showTokenWeight(tk) {
      const w = Number(tk.weight || 0)
      const direction = w >= 0 ? '倾向垃圾判定' : '倾向正常判定'
      confirm({
        title: '关键词权重',
        content: `关键词「${tk.token}」\n权重贡献：${w >= 0 ? '+' : ''}${w.toFixed(4)}\n（${direction}）`,
        showCancel: false,
        confirmText: '关闭'
      })
    },
    generateCSV() {
      if (!this.items.length) return ''
      const headers = ['文本', '判定结果', '分类标签', '置信度', '垃圾概率', '正常概率', '风险关键词']
      const rows = this.items.map((item) => {
        const prediction = item.prediction === 'spam' ? '垃圾信息' : '正常信息'
        const categoryLabel = item.category_label || ''
        const confidence = item.confidence_text || '0%'
        const spamProb = this.formatPercent(item.spam_probability, 4)
        const hamProb = this.formatPercent(item.ham_probability, 4)
        const tokens = (item.reason_tokens || []).map((t) => t.token || t).join('; ')
        const text = (item.text || '').replace(/"/g, '""')
        const tokensEscaped = tokens.replace(/"/g, '""')
        return `"${text}","${prediction}","${categoryLabel}","${confidence}","${spamProb}","${hamProb}","${tokensEscaped}"`
      })
      return [headers.join(','), ...rows].join('\n')
    },
    async exportXLSX() {
      if (!this.items.length) {
        toast('暂无识别结果可导出', 'error')
        return
      }
      this.exporting = true
      try {
        const res = await request({
          url: '/spam/export/xlsx',
          method: 'POST',
          data: { items: this.items },
          responseType: 'blob'
        })
        const blob = new Blob([res.data], {
          type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        })
        const ts = new Date().toISOString().slice(0, 19).replace(/[T:]/g, '-')
        const filename = `batch_detect_${ts}.xlsx`
        const link = document.createElement('a')
        link.href = URL.createObjectURL(blob)
        link.download = filename
        document.body.appendChild(link)
        link.click()
        setTimeout(() => {
          URL.revokeObjectURL(link.href)
          document.body.removeChild(link)
        }, 0)
        toast('导出成功', 'success')
      } catch (err) {
        toast('导出失败', 'error')
      } finally {
        this.exporting = false
      }
    },
    async copyCSV() {
      if (!this.items.length) {
        toast('暂无识别结果可复制', 'error')
        return
      }
      const csv = this.generateCSV()
      try {
        await navigator.clipboard.writeText(csv)
        toast('CSV 内容已复制到剪贴板', 'success')
      } catch (err) {
        toast('复制失败，请手动选择文本', 'error')
      }
    }
  }
}
</script>
