<template>
  <div class="lepao-proxy-page">
    <Breadcrumb :items="['网站管理', '乐跑出口代理']" />

    <a-spin :loading="pageLoading">
      <a-card class="hero-card" :bordered="false">
        <div class="hero-inner">
          <div class="hero-title">
            <span class="t1">乐跑出站代理</span>
            <a-tag color="arcoblue" size="small">青果 · 通道提取</a-tag>
          </div>
          <div class="hero-desc">
            对学校 HTTPS 接口经 HTTP 代理出口；密钥在服务端 <code>qgChannelProxy</code>。
            <a-link href="https://www.qg.net/doc/1850.html" target="_blank" rel="noopener">资源地区 API</a-link>
            ·
            <a-link href="https://www.qg.net/doc/1846.html" target="_blank" rel="noopener">提取 IP</a-link>
          </div>
        </div>
      </a-card>

      <a-row :gutter="16" style="margin-top: 16px">
        <a-col :span="24">
          <a-card title="当前状态" :bordered="false" class="panel">
            <a-descriptions :column="2" bordered size="small">
              <a-descriptions-item label="extractKey">
                <a-tag :color="status?.extract_key_configured ? 'green' : 'orangered'">
                  {{ status?.extract_key_configured ? '已配置' : '未配置' }}
                </a-tag>
              </a-descriptions-item>
              <a-descriptions-item label="代理账密">
                <a-tag :color="status?.proxy_auth_configured ? 'cyan' : 'gray'">
                  {{ status?.proxy_auth_configured ? '已配置' : '可选（白名单可不填）' }}
                </a-tag>
              </a-descriptions-item>
              <a-descriptions-item label="代理节点 server">
                <span class="mono">{{ status?.current_proxy?.server ?? '—' }}</span>
              </a-descriptions-item>
              <a-descriptions-item label="节点 IP 属地">
                <a-tag color="purple">{{ status?.current_proxy?.node_region ?? '—' }}</a-tag>
              </a-descriptions-item>
              <a-descriptions-item label="出口 IP proxy_ip">
                <span class="mono">{{ status?.current_proxy?.proxy_ip ?? '—' }}</span>
              </a-descriptions-item>
              <a-descriptions-item label="出口 IP 属地">
                <a-tag color="gold">{{ status?.current_proxy?.proxy_ip_region ?? '—' }}</a-tag>
              </a-descriptions-item>
              <a-descriptions-item label="deadline" :span="2">
                {{ status?.current_proxy?.deadline ?? '—' }}
                <a-tag
                  v-if="status?.current_proxy"
                  size="small"
                  :color="status?.current_proxy?.stale ? 'orangered' : 'green'"
                  style="margin-left: 8px"
                >
                  {{ status?.current_proxy?.stale ? '临近/已过期' : '有效期内' }}
                </a-tag>
              </a-descriptions-item>
            </a-descriptions>
          </a-card>
        </a-col>
      </a-row>

      <a-row :gutter="16" style="margin-top: 16px">
        <a-col :xs="24" :lg="16">
          <a-card title="筛选与路由" :bordered="false" class="panel">
            <a-form :model="form" layout="vertical">
              <a-form-item label="启用青果出站">
                <a-switch v-model="form.proxy_enabled" />
              </a-form-item>

              <a-form-item label="从青果可选资源勾选地区（支持搜索）">
                <a-space direction="vertical" fill style="width: 100%">
                  <a-space wrap>
                    <a-button size="mini" type="outline" @click="loadResources" :loading="resLoading">
                      刷新资源列表
                    </a-button>
                    <a-checkbox v-model="onlyAvailableRes">仅显示「可提取」</a-checkbox>
                  </a-space>
                  <a-select
                    v-model="selectedAreaCodes"
                    multiple
                    allow-search
                    allow-clear
                    :loading="resLoading"
                    :options="filteredResourceOptions"
                    :placeholder="resourcePlaceholder"
                    :filter-option="filterResourceOption"
                    style="width: 100%"
                  />
                  <div class="hint-muted">
                    将写入后端 area 字段（逗号分隔，与青果调试工具一致）。也可在下方微调编码。
                  </div>
                  <a-input
                    v-model="form.area"
                    allow-clear
                    placeholder="area 编码，逗号分隔（与上方选择同步，失焦后与多选对齐）"
                    @blur="syncSelectedFromArea"
                  />
                </a-space>
              </a-form-item>

              <a-form-item label="排除地区 area_ex">
                <a-input v-model="form.area_ex" allow-clear placeholder="可选，逗号分隔" />
              </a-form-item>
              <a-form-item label="运营商 isp">
                <a-select v-model="form.isp" allow-clear placeholder="不筛选">
                  <a-option :value="undefined">不筛选</a-option>
                  <a-option :value="1">电信</a-option>
                  <a-option :value="2">移动</a-option>
                  <a-option :value="3">联通</a-option>
                </a-select>
              </a-form-item>
              <a-form-item label="distinct 去重提取">
                <a-switch v-model="form.distinct_extract" />
              </a-form-item>
              <a-form-item label="保存时清空 Redis 当前 IP">
                <a-checkbox v-model="form.invalidate_cache">清空（下次强制重新提取）</a-checkbox>
              </a-form-item>
              <a-space>
                <a-button type="primary" @click="saveConfig" :loading="saving">保存配置</a-button>
                <a-button @click="loadStatus">刷新状态</a-button>
              </a-space>
            </a-form>
          </a-card>
        </a-col>
        <a-col :xs="24" :lg="8">
          <a-card title="说明" :bordered="false" class="panel side-tips">
            <ul class="tips-list">
              <li>资源列表来自青果「查询资源地区」接口，请以控制台实际可用为准。</li>
              <li>日志表中「出口 IP」为青果 proxy_ip；「出口属地」仅据此 IP 解析（ip2region）。</li>
              <li>单通道时请避免频繁作废 IP；后端已对 /get 与 POST 做多轮退让重试。</li>
            </ul>
          </a-card>
        </a-col>
      </a-row>

      <a-card title="出站与切换摘要" class="panel log-card" style="margin-top: 16px" :bordered="false">
        <template #extra>
          <a-space>
            <a-button
              type="primary"
              status="danger"
              :disabled="!selectedLogKeys.length"
              :loading="logDeleting"
              @click="deleteSelectedLogs"
            >
              删除所选（{{ selectedLogKeys.length }}）
            </a-button>
            <a-button type="outline" status="danger" :loading="logDeleting" @click="confirmDeleteAllLogs">
              清空全部
            </a-button>
          </a-space>
        </template>
        <a-table
          v-model:selected-keys="selectedLogKeys"
          row-key="id"
          :row-selection="{ type: 'checkbox', showCheckedAll: true }"
          :data="logData"
          :loading="logLoading"
          :bordered="false"
          :pagination="{
            showPageSize: true,
            showJumper: true,
            showTotal: true,
            pageSize: pagination.pagesize,
            current: pagination.current,
            total: pagination.total
          }"
          @page-change="handlePageChange"
          @page-size-change="handlePageSizeChange"
        >
          <template #columns>
            <a-table-column title="时间" :width="178">
              <template #cell="{ record }">{{ strTime(record.created_at) }}</template>
            </a-table-column>
            <a-table-column title="类型" :width="120">
              <template #cell="{ record }">
                <a-tag size="small" :color="record.event_color">{{ record.event_label }}</a-tag>
              </template>
            </a-table-column>
            <a-table-column title="节点 server" data-index="server" :width="160" ellipsis tooltip />
            <a-table-column title="出口 IP" :width="130">
              <template #cell="{ record }">
                <span class="mono">{{ record.egress_ip ?? '—' }}</span>
              </template>
            </a-table-column>
            <a-table-column title="出口属地" :width="200">
              <template #cell="{ record }">
                <span v-if="!record.egress_ip" class="hint-muted">—</span>
                <a-tag v-else color="cyan" size="small">{{ shortenRegion(record.egress_region || '未知') }}</a-tag>
              </template>
            </a-table-column>
            <a-table-column title="摘要">
              <template #cell="{ record }">
                <div class="summary-text">{{ record.summary }}</div>
              </template>
            </a-table-column>
            <a-table-column title="操作" fixed="right" :width="88">
              <template #cell="{ record }">
                <a-popconfirm content="删除该条日志？" @ok="deleteOneLog(record.id)">
                  <a-button type="text" size="mini" status="danger">删除</a-button>
                </a-popconfirm>
              </template>
            </a-table-column>
          </template>
        </a-table>
      </a-card>
    </a-spin>
  </div>
</template>

<script setup>
import { reactive, ref, computed, watch, onMounted } from 'vue'
import { Notification, Modal } from '@arco-design/web-vue'
import {
  getAdminLepaoProxyStatus,
  postAdminLepaoProxyConfig,
  getAdminLepaoProxyLogs,
  postAdminLepaoProxyLogsDelete,
  getAdminLepaoProxyResources
} from '@/api/lepao'

const pageLoading = ref(false)
const logLoading = ref(false)
const logDeleting = ref(false)
const selectedLogKeys = ref([])
const saving = ref(false)
const status = ref(null)
const logData = ref([])
const resourcesRaw = ref([])
const resLoading = ref(false)
const onlyAvailableRes = ref(true)
const selectedAreaCodes = ref([])

const pagination = reactive({
  total: 0,
  current: 1,
  pagesize: 20
})

const form = reactive({
  proxy_enabled: false,
  area: '',
  area_ex: '',
  isp: undefined,
  distinct_extract: true,
  invalidate_cache: false
})

watch(
  selectedAreaCodes,
  (v) => {
    form.area = Array.isArray(v) && v.length ? v.join(',') : ''
  },
  { deep: true }
)

const filteredResourceOptions = computed(() => {
  const rows = resourcesRaw.value || []
  let list = onlyAvailableRes.value ? rows.filter((r) => r.available === true) : [...rows]
  return list.map((r) => {
    const code = String(r.area_code ?? '')
    const isp = r.isp ?? ''
    const ok = r.available ? '可提取' : '暂不可用'
    return {
      label: `[${code}] ${r.area ?? ''} · ${isp} · ${ok}`,
      value: code
    }
  })
})

const resourcePlaceholder = computed(() =>
  resourcesRaw.value.length ? '搜索城市 / 运营商 / 编码…' : '请先点击「刷新资源列表」'
)

function filterResourceOption(input, option) {
  return String(option?.label ?? '')
    .toLowerCase()
    .includes(String(input || '').toLowerCase())
}

function shortenRegion(r) {
  if (!r || r === '未知') return '未知'
  const parts = String(r).split(' · ')
  return parts.slice(-2).join(' · ') || r
}

const strTime = (t) =>
  t == null
    ? '—'
    : new Date(Number(t)).toLocaleString('zh-CN', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit'
      })

const syncSelectedFromArea = () => {
  selectedAreaCodes.value = form.area
    ? String(form.area)
        .split(',')
        .map((s) => s.trim())
        .filter(Boolean)
        .map(String)
    : []
}

const applyStatus = (data) => {
  status.value = data
  form.proxy_enabled = !!data?.proxy_enabled
  form.area = data?.area ?? ''
  form.area_ex = data?.area_ex ?? ''
  form.isp = data?.isp === null || data?.isp === '' ? undefined : Number(data.isp)
  form.distinct_extract = data?.distinct_extract !== false
  syncSelectedFromArea()
}

const loadStatus = async () => {
  pageLoading.value = true
  try {
    const res = await getAdminLepaoProxyStatus({})
    if (!res || res.code !== 0) {
      Notification.error({ title: '读取状态失败', content: res?.msg ?? '请稍后再试' })
      return
    }
    applyStatus(res.data)
  } finally {
    pageLoading.value = false
  }
}

const loadResources = async () => {
  resLoading.value = true
  try {
    const res = await getAdminLepaoProxyResources({})
    if (!res || res.code !== 0) {
      Notification.error({ title: '资源列表获取失败', content: res?.msg ?? '请检查 extractKey 与网络' })
      return
    }
    resourcesRaw.value = res.data || []
    Notification.success({ title: '资源列表已更新', content: `共 ${resourcesRaw.value.length} 条` })
  } finally {
    resLoading.value = false
  }
}

const loadLogs = async () => {
  logLoading.value = true
  try {
    const res = await getAdminLepaoProxyLogs({
      current: pagination.current,
      pagesize: pagination.pagesize
    })
    if (!res || res.code !== 0) {
      Notification.error({ title: '读取日志失败', content: res?.msg ?? '请稍后再试' })
      return
    }
    logData.value = res.data || []
    pagination.total = res.pagination?.total || 0
    selectedLogKeys.value = []
  } finally {
    logLoading.value = false
  }
}

const deleteOneLog = async (id) => {
  logDeleting.value = true
  try {
    const res = await postAdminLepaoProxyLogsDelete({ ids: [id] })
    if (!res || res.code !== 0) {
      Notification.error({ title: '删除失败', content: res?.msg ?? '请稍后再试' })
      return
    }
    Notification.success({ title: '已删除', content: '' })
    await loadLogs()
  } finally {
    logDeleting.value = false
  }
}

const deleteSelectedLogs = async () => {
  if (!selectedLogKeys.value.length) return
  logDeleting.value = true
  try {
    const res = await postAdminLepaoProxyLogsDelete({ ids: selectedLogKeys.value.map(Number) })
    if (!res || res.code !== 0) {
      Notification.error({ title: '删除失败', content: res?.msg ?? '请稍后再试' })
      return
    }
    Notification.success({ title: `已删除 ${res.data?.deleted ?? selectedLogKeys.value.length} 条`, content: '' })
    pagination.current = 1
    await loadLogs()
  } finally {
    logDeleting.value = false
  }
}

const confirmDeleteAllLogs = () => {
  Modal.confirm({
    title: '清空全部代理日志',
    content: '将删除表中全部 lepao_proxy_log 记录，不可恢复。',
    okText: '确认清空',
    modalStyle: { maxWidth: '420px' },
    okButtonProps: { status: 'danger' },
    onOk: async () => {
      logDeleting.value = true
      try {
        const res = await postAdminLepaoProxyLogsDelete({ purge_all: 1 })
        if (!res || res.code !== 0) {
          Notification.error({ title: '清空失败', content: res?.msg ?? '请稍后再试' })
          return
        }
        Notification.success({ title: '已清空日志', content: '' })
        pagination.current = 1
        await loadLogs()
      } finally {
        logDeleting.value = false
      }
    }
  })
}

const saveConfig = async () => {
  saving.value = true
  try {
    const res = await postAdminLepaoProxyConfig({
      proxy_enabled: form.proxy_enabled ? 1 : 0,
      area: form.area,
      area_ex: form.area_ex,
      isp: form.isp === undefined ? '' : form.isp,
      distinct_extract: form.distinct_extract ? 1 : 0,
      invalidate_cache: form.invalidate_cache ? 1 : 0
    })
    if (!res || res.code !== 0) {
      Notification.error({ title: '保存失败', content: res?.msg ?? '请稍后再试' })
      return
    }
    Notification.success({ title: '已保存', content: '' })
    form.invalidate_cache = false
    await loadStatus()
    await loadLogs()
  } finally {
    saving.value = false
  }
}

const handlePageChange = (page) => {
  pagination.current = page
  loadLogs()
}

const handlePageSizeChange = (size) => {
  pagination.pagesize = size
  pagination.current = 1
  loadLogs()
}

onMounted(async () => {
  await loadStatus()
  await loadLogs()
})
</script>

<style scoped lang="less">
.lepao-proxy-page {
  padding: 16px 20px 32px;
  max-width: 1280px;
  margin: 0 auto;
}

.hero-card {
  background: linear-gradient(135deg, var(--color-bg-2), var(--color-fill-2));
}

.hero-inner {
  padding: 4px 0;
}

.hero-title {
  display: flex;
  align-items: center;
  gap: 12px;

  .t1 {
    font-size: 20px;
    font-weight: 600;
    color: var(--color-text-1);
  }
}

.hero-desc {
  margin-top: 10px;
  color: var(--color-text-2);
  font-size: 13px;
  line-height: 1.6;

  code {
    padding: 0 6px;
    border-radius: 4px;
    background: var(--color-fill-3);
    font-size: 12px;
  }
}

.panel {
  border-radius: 12px;

  &.log-card {
    box-shadow: 0 1px 4px rgb(0 0 0 / 4%);
  }
}

.mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
  font-size: 13px;
}

.side-tips .tips-list {
  margin: 0;
  padding-left: 18px;
  color: var(--color-text-2);
  font-size: 13px;
  line-height: 1.85;
}

.summary-text {
  font-size: 13px;
  line-height: 1.65;
  color: var(--color-text-2);
}

.hint-muted {
  color: var(--color-text-3);
  font-size: 12px;
}

</style>
