<template>
    <div class="yeji-page">
        <!-- ── 顶部筛选 ────────────────────────────── -->
        <el-card class="filter-card" shadow="never">
            <div class="filter-surface">
                <div class="filter-row filter-row--top">
                    <div class="filter-field">
                        <span class="lbl">渠道来源</span>
                        <el-select
                            v-model="selectedChannel"
                            filterable
                            placeholder="渠道筛选"
                            class="filter-select filter-select--channel"
                            :loading="channelOptionsLoading"
                            @change="loadData"
                        >
                            <el-option label="全部" value="" />
                            <el-option-group
                                v-for="g in channelGroups"
                                :key="g.group_name"
                                :label="g.group_name"
                            >
                                <el-option
                                    v-for="ch in g.channels"
                                    :key="ch.channel_code"
                                    :label="ch.channel_name"
                                    :value="ch.channel_code"
                                >
                                    <div class="channel-opt-row">
                                        <span class="opt-name">{{ ch.channel_name }}</span>
                                        <span class="opt-count">{{
                                            ch.customer_count > 0 ? ch.customer_count : ''
                                        }}</span>
                                    </div>
                                </el-option>
                            </el-option-group>
                        </el-select>
                    </div>

                    <div class="filter-field filter-field--wide">
                        <span class="lbl">展示部门</span>
                        <el-select
                            v-model="selectedDeptIds"
                            multiple
                            collapse-tags
                            collapse-tags-tooltip
                            filterable
                            placeholder="默认：所有「中心」部门"
                            class="filter-select filter-select--dept"
                            :loading="deptOptionsLoading"
                        >
                            <el-option
                                v-for="d in deptOptions"
                                :key="d.id"
                                :label="d.path || d.name"
                                :value="d.id"
                            />
                        </el-select>
                    </div>

                    <div class="filter-field filter-field--date-top">
                        <span class="lbl">日期范围</span>
                        <el-date-picker
                            v-model="customRange"
                            type="daterange"
                            value-format="YYYY-MM-DD"
                            start-placeholder="开始"
                            end-placeholder="结束"
                            :clearable="true"
                            :shortcuts="dateShortcuts"
                            class="filter-date-picker"
                        />
                    </div>

                    <div class="filter-actions">
                        <el-button
                            type="primary"
                            class="filter-btn filter-btn--query"
                            round
                            :loading="loading"
                            @click="loadData"
                        >
                            <el-icon class="filter-btn__icon"><Search /></el-icon>
                            查询
                        </el-button>
                        <el-button
                            plain
                            class="filter-btn filter-btn--reset"
                            round
                            :disabled="loading"
                            @click="handleReset"
                        >
                            <el-icon class="filter-btn__icon"><RefreshRight /></el-icon>
                            重置
                        </el-button>
                    </div>
                </div>

                <p class="filter-hint">
                    未选日期时展示「本月 / 本周 / 今日 / 昨日」四张汇总表；选日期后为单表。排行榜默认按今日（见下方说明）。
                </p>

                <div class="filter-quick">
                    <span class="filter-quick__title">快捷日期</span>
                    <div class="date-pills" role="group" aria-label="快捷日期">
                        <button
                            v-for="sc in dateShortcuts"
                            :key="sc.text"
                            type="button"
                            class="date-pill"
                            @click="applyDateShortcut(sc)"
                        >
                            {{ sc.text }}
                        </button>
                    </div>
                </div>
            </div>
        </el-card>

        <!-- <el-alert
            v-if="channelFilterNote"
            :title="channelFilterNote"
            type="info"
            show-icon
            :closable="false"
            class="filter-alert"
        /> -->
        <!-- ── 目标进度卡片 ── -->
        <div
            v-if="targetProgressCard || targetProgressLoading"
            v-loading="targetProgressLoading"
            class="tp-wrap"
        >
            <div v-if="targetProgressCard" class="tp-card">
                <div class="tp-card__title">{{ targetProgressCard.title }}</div>
                <div class="tp-card__body">
                    <div
                        v-for="sec in targetProgressCard.sections"
                        :key="sec.dept_id"
                        class="tp-section"
                    >
                        <div class="tp-section__head">
                            <span class="tp-section__name">{{ sec.dept_name }}目标</span>
                            <span class="tp-section__target">{{ formatMoneyW(sec.target_amount) }}</span>
                        </div>
                        <table class="tp-table">
                            <tbody>
                                <tr>
                                    <td class="tp-lbl">昨日诊金</td>
                                    <td class="tp-val">{{ formatInt(sec.yesterday_amount) }}</td>
                                </tr>
                                <tr v-if="sec.douyin_amount !== null">
                                    <td class="tp-lbl">抖音总诊金</td>
                                    <td class="tp-val">{{ formatInt(sec.douyin_amount) }}</td>
                                </tr>
                                <tr v-if="sec.tuifen_amount !== null">
                                    <td class="tp-lbl">推粉总诊金</td>
                                    <td class="tp-val">{{ formatInt(sec.tuifen_amount) }}</td>
                                </tr>
                                <tr>
                                    <td class="tp-lbl">总诊金</td>
                                    <td class="tp-val tp-val--total">{{ formatInt(sec.total_amount) }}</td>
                                </tr>
                                <tr>
                                    <td class="tp-lbl">目标进度</td>
                                    <td class="tp-val">{{ formatMoney(sec.target_progress) }}</td>
                                </tr>
                                <tr>
                                    <td class="tp-lbl">完成进度</td>
                                    <td class="tp-val" :class="achievementClass(sec.completion_rate)">{{ formatAchievement(sec.completion_rate) }}</td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>

        <!-- ── 业绩表（4 张/N 张） ────────────────── -->
        <div v-loading="loading" class="tables-wrap">
            <div v-if="!loading && tables.length === 0" class="empty-tip">
                <el-empty description="暂无数据" />
            </div>

            <div
                v-for="(tb, idx) in tables"
                :key="idx"
                class="yeji-table"
            >
                <div class="yeji-table__header">
                    {{ buildTableTitle(tb) }}
                </div>
                <table class="yeji-table__body">
                    <thead>
                        <tr>
                            <th class="col-dept">部门</th>
                            <th>
                                <span>进线数据</span>
                                <el-tooltip placement="top" effect="dark" :show-after="200">
                                    <template #content>
                                        <div style="max-width: 320px; line-height: 1.7; font-size: 12px">
                                            add_external_contact 事件数，按接待企微成员归属部门；定渠道时须客户带对应企微标签。<br />
                                            <template v-if="tb.channel_name">
                                                <b>名称含「二中心」的部门</b>在选定渠道下进线计 <b>0</b>。
                                            </template>
                                        </div>
                                    </template>
                                    <el-icon class="col-info"><InfoFilled /></el-icon>
                                </el-tooltip>
                            </th>
                            <th>
                                <span>合计业绩</span>
                                <el-tooltip placement="top" effect="dark" :show-after="200">
                                    <template #content>
                                        <div style="max-width: 300px; line-height: 1.7; font-size: 12px">
                                            按订单<b>创建时间</b>统计，与「处方订单列表」业绩合计口径一致。<br />
                                            <b>不受渠道筛选影响</b>，展示部门下全部订单。
                                        </div>
                                    </template>
                                    <el-icon class="col-info"><InfoFilled /></el-icon>
                                </el-tooltip>
                            </th>
                            <th v-if="tb.channel_name" class="col-completed">
                                <span>{{ buildChannelColTitle(tb, '业绩') }}</span>
                                <el-tooltip placement="top" effect="dark" :show-after="200">
                                    <template #content>
                                        <div style="max-width: 340px; line-height: 1.7; font-size: 12px">
                                            与「处方订单列表」业绩<b>同口径</b>：按订单 <b>create_time</b> 归日，<br />
                                            fulfillment_status ≠ 4。<br />
                                            渠道判定仅用 EXISTS：该患者有任一挂号 <b>channels 命中字典 + status=3</b>（不限挂号时点）。
                                        </div>
                                    </template>
                                    <el-icon class="col-info"><InfoFilled /></el-icon>
                                </el-tooltip>
                            </th>
                            <th>接诊诊单</th>
                            <th v-if="tb.channel_name" class="col-completed">
                                <span>{{ buildChannelColTitle(tb, '成交单') }}</span>
                                <el-tooltip placement="top" effect="dark" :show-after="200">
                                    <template #content>
                                        <div style="max-width: 320px; line-height: 1.7; font-size: 12px">
                                            与「{{ tb.channel_name }}业绩」同源：统计区间内 <b>非取消业务订单</b> 条数（fulfillment_status ≠ 4），<br />
                                            按订单 <b>create_time</b> 归日；渠道判定同业绩列（患者须有对应 channels 的已完成挂号）。
                                        </div>
                                    </template>
                                    <el-icon class="col-info"><InfoFilled /></el-icon>
                                </el-tooltip>
                            </th>
                            <th>平均单价</th>
                            <th v-if="tb.channel_name" class="col-completed">
                                <span>{{ buildChannelColTitle(tb, '客单价') }}</span>
                                <el-tooltip placement="top" effect="dark" :show-after="200">
                                    <template #content>
                                        <div style="max-width: 280px; line-height: 1.7; font-size: 12px">
                                            {{ tb.channel_name }}业绩 ÷ {{ tb.channel_name }}成交单数（均值）。
                                        </div>
                                    </template>
                                    <el-icon class="col-info"><InfoFilled /></el-icon>
                                </el-tooltip>
                            </th>
                            <th>
                                <span>ROI</span>
                                <el-tooltip placement="top" effect="dark" :show-after="200">
                                    <template #content>
                                        <div style="max-width: 320px; line-height: 1.7; font-size: 12px">
                                            <template v-if="tb.channel_name">
                                                有渠道时：<b>合计行 ROI</b> = <b>{{ tb.channel_name }}业绩合计</b>（与上表该渠道业绩列合计一致，<b>不含名称含「二中心」的部门</b>）÷ <b>投放成本合计</b>。<br />
                                                部门行 ROI = 该部门 <b>{{ tb.channel_name }}业绩</b> ÷ 该部门 <b>投放成本</b>；二中心部门该渠道业绩与进线为 0。与「合计业绩」列无关。
                                            </template>
                                            <template v-else>
                                                <b>合计业绩</b> ÷ <b>投放成本</b>。投放成本按各部门<b>进线条数占比</b>从总成本中分摊。
                                            </template>
                                        </div>
                                    </template>
                                    <el-icon class="col-info"><InfoFilled /></el-icon>
                                </el-tooltip>
                            </th>
                            <th>
                                <span>投放成本</span>
                                <el-tooltip placement="top" effect="dark" :show-after="200">
                                    <template #content>
                                        <div style="max-width: 320px; line-height: 1.7; font-size: 12px">
                                            区间与渠道与账务表一致后得到<b>总投放成本</b>；<b>单进线成本</b> = 总成本 ÷ 各展示部门<b>进线合计</b>；<br />
                                            各部门行投放成本 = 单进线成本 × 该部门进线（四舍五入尾差并入进线最多的部门）。
                                        </div>
                                    </template>
                                    <el-icon class="col-info"><InfoFilled /></el-icon>
                                </el-tooltip>
                            </th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr v-for="r in tb.rows" :key="r.dept_id">
                            <td class="col-dept">{{ r.dept_name }}</td>
                            <td>{{ formatInt(r.lead_count) }}</td>
                            <td>{{ formatMoney(r.performance_amount) }}</td>
                            <td v-if="tb.channel_name" class="col-completed">{{ formatMoney(r.completed_performance_amount) }}</td>
                            <td>{{ formatInt(r.consult_count) }}</td>
                            <td v-if="tb.channel_name" class="col-completed">{{ formatInt(r.channel_consult_count) }}</td>
                            <td>{{ formatNumber(r.avg_price) }}</td>
                            <td v-if="tb.channel_name" class="col-completed">{{ formatNumber(r.channel_avg_price) }}</td>
                            <td :class="roiClass(r.roi)">{{ formatRoi(r.roi) }}</td>
                            <td>{{ formatMoney(r.cost_amount) }}</td>
                        </tr>
                        <tr class="total-row">
                            <td class="col-dept">合计</td>
                            <td>{{ formatInt(tb.total.lead_count) }}</td>
                            <td>{{ formatMoney(tb.total.performance_amount) }}</td>
                            <td v-if="tb.channel_name" class="col-completed">{{ formatMoney(tb.total.completed_performance_amount) }}</td>
                            <td>{{ formatInt(tb.total.consult_count) }}</td>
                            <td v-if="tb.channel_name" class="col-completed">{{ formatInt(tb.total.channel_consult_count) }}</td>
                            <td>{{ formatNumber(tb.total.avg_price) }}</td>
                            <td v-if="tb.channel_name" class="col-completed">{{ formatNumber(tb.total.channel_avg_price) }}</td>
                            <td :class="roiClass(tb.total.roi)">{{ formatRoi(tb.total.roi) }}</td>
                            <td>{{ formatMoney(tb.total.cost_amount) }}</td>
                        </tr>
                    </tbody>
                </table>
                <div class="yeji-table__foot">
                    <span>区间：{{ tb.start_date }} ~ {{ tb.end_date }}</span>
                    <span v-if="tb.channel_name"> · 渠道：{{ tb.channel_name }}</span>
                    <span v-if="tb.total.cost_per_lead != null && tb.total.cost_per_lead > 0">
                        · 单进线成本：{{ formatMoney(tb.total.cost_per_lead) }} 元
                    </span>
                </div>
            </div>
        </div>

        <!-- 医助排行榜：选自定义日期时与所选区间一致；未选时仅统计今日 -->
        <div
            v-if="leaderboardBlock || leaderboardsLoading"
            class="leaderboards-wrap"
            v-loading="leaderboardsLoading"
        >
            <template v-if="leaderboardBlock">
              
                <p class="leaderboard-hint">
                    {{ leaderboardBlock.range_note }}
                    <span class="muted">
                        统计区间：{{ leaderboardBlock.start_date }}～{{ leaderboardBlock.end_date }}
                        <template v-if="!customRange">
                            （未选自定义日期时排行榜仅统计今日，与上方多张业绩表区间无关）
                        </template>
                    </span>
                </p>
                <div class="tables-wrap">
                    <template v-for="lb in leaderboardBlock.leaderboards" :key="lb.dept_id">
                        <div v-if="lb.rows.length > 0" class="yeji-table leaderboard-table">
                            <div class="yeji-table__header">
                                {{ lb.dept_name }} · 医助排行榜
                                <span v-if="leaderboardBlock.channel_name" class="leaderboard-sub">
                                    （{{ leaderboardBlock.channel_name }}）
                                </span>
                            </div>
                            <table class="yeji-table__body">
                                <thead>
                                    <tr>
                                        <th class="col-rank">排名</th>
                                        <th class="col-abbr">部门</th>
                                        <th class="col-name">姓名</th>
                                        <th>诊金</th>
                                        <th>接诊率<br /><span class="th-sub">（元/进线）</span></th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <tr v-for="r in lb.rows" :key="r.admin_id">
                                        <td class="col-rank">{{ r.rank }}</td>
                                        <td class="col-abbr">{{ r.dept_abbr }}</td>
                                        <td class="col-name">{{ r.name }}</td>
                                        <td>{{ formatMoney(r.fee_amount) }}</td>
                                        <td>{{ formatMoney(r.consult_rate) }}</td>
                                    </tr>
                                </tbody>
                            </table>
                            <div class="yeji-table__foot yeji-table__foot--left">
                                <span>诊金单位：元 · 接诊率 = 诊金 ÷ 进线（元/进线，保留 1 位小数；有渠道时进线含标签过滤与二中心规则）</span>
                            </div>
                        </div>
                    </template>
                </div>
                <div
                    v-if="!leaderboardsLoading && leaderboardVisibleTables === 0"
                    class="empty-tip leaderboard-empty"
                >
                    <el-empty description="当前筛选下暂无医助排行数据" />
                </div>
            </template>
        </div>
    </div>
</template>

<script lang="ts" setup>
import { computed, onMounted, ref } from 'vue'
import { Search, RefreshRight, InfoFilled } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import {
    yejiStatsChannelOptions,
    yejiStatsDeptOptions,
    yejiStatsLeaderboard,
    yejiStatsMulti,
    yejiStatsOverview,
} from '@/api/stats'
import { deptPerformanceTargetMonthMatrix } from '@/api/finance'

interface DeptOption {
    id: number
    name: string
    pid: number
    path: string
}

interface ChannelOption {
    channel_code: string
    channel_name: string
    source_tag_id: string
    source_group_name: string
    customer_count: number
}

interface ChannelGroup {
    group_name: string
    channels: ChannelOption[]
}

interface YejiRow {
    dept_id: number
    dept_name: string
    lead_count: number
    consult_count: number
    channel_consult_count: number
    performance_amount: number
    completed_performance_amount: number
    avg_price: number | null
    channel_avg_price: number | null
    cost_amount: number
    roi: number | null
}

interface YejiTable {
    label: string
    start_date: string
    end_date: string
    channel_code: string
    channel_name: string
    channel_group: string
    channel_filter_note: string
    rows: YejiRow[]
    total: {
        lead_count: number
        consult_count: number
        channel_consult_count: number
        performance_amount: number
        completed_performance_amount: number
        avg_price: number | null
        channel_avg_price: number | null
        cost_amount: number
        cost_per_lead: number | null
        roi: number | null
    }
}

interface LeaderboardPack {
    start_date: string
    end_date: string
    channel_code: string
    channel_name: string
    channel_filter_note: string
    range_note: string
    leaderboards: Array<{
        dept_id: number
        dept_name: string
        dept_abbr: string
        rows: Array<{
            rank: number
            admin_id: number
            name: string
            dept_abbr: string
            fee_amount: number
            consult_rate: number
        }>
    }>
}

const loading = ref(false)
const deptOptions = ref<DeptOption[]>([])
const deptOptionsLoading = ref(false)
const selectedDeptIds = ref<number[]>([])
const channelGroups = ref<ChannelGroup[]>([])
const channelOptionsLoading = ref(false)
const selectedChannel = ref<string>('')
const customRange = ref<[string, string] | null>(null)
const tables = ref<YejiTable[]>([])
const leaderboardBlock = ref<LeaderboardPack | null>(null)
const leaderboardsLoading = ref(false)

// ── 目标进度卡片 ──────────────────────────────
interface TargetProgressSection {
    dept_id: number
    dept_name: string
    target_amount: number
    total_amount: number
    yesterday_amount: number
    douyin_amount: number | null   // 名称含「自媒体1」的子部门合计
    tuifen_amount: number | null   // 名称含「自媒体3」或「自媒体4」的子部门合计
    target_progress: number        // 按已过天数均摊的目标进度
    completion_rate: number | null // 总诊金 / 目标金额
}
interface TargetProgressCard {
    title: string
    sections: TargetProgressSection[]
}
const targetProgressCard = ref<TargetProgressCard | null>(null)
const targetProgressLoading = ref(false)

function ymCurrent(): string {
    const d = new Date()
    return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`
}
function daysInMonth(ym: string): number {
    const [y, m] = ym.split('-').map(Number)
    return new Date(y, m, 0).getDate()
}

async function loadTargetProgress() {
    targetProgressLoading.value = true
    targetProgressCard.value = null
    try {
        const ym = ymCurrent()
        const targetRes: any = await deptPerformanceTargetMonthMatrix({ year_month: ym })
        const treeRows: any[] = targetRes?.rows ?? []
        if (!treeRows.length) return

        // 从目标树平铺，找到 depth>=1 且目标>0 的节点作为卡片分区
        function flatWithDepth(nodes: any[], depth = 0): Array<{ node: any; depth: number }> {
            const r: Array<{ node: any; depth: number }> = []
            for (const n of nodes ?? []) {
                r.push({ node: n, depth })
                r.push(...flatWithDepth(n.children ?? [], depth + 1))
            }
            return r
        }
        const all = flatWithDepth(treeRows)
        const cardDepts = all
            .filter(x => x.depth >= 1 && Number(x.node.target_amount) > 0)
            .map(x => x.node)
        if (!cardDepts.length) return

        // 用 deptOptions（完整部门列表，含 pid）做层级查找
        // 目标树只包含有目标的节点，无法得到 0 目标的子部门（如自媒体1/3/4）
        function descIdsFromOptions(deptId: number): number[] {
            const result: number[] = []
            const queue = [deptId]
            while (queue.length) {
                const pid = queue.shift()!
                for (const d of deptOptions.value) {
                    if (Number(d.pid) === pid) {
                        result.push(d.id)
                        queue.push(d.id)
                    }
                }
            }
            return result
        }

        const allIds = new Set<number>()
        const specs = cardDepts.map(dept => {
            const deptId = Number(dept.dept_id)
            const childIds = descIdsFromOptions(deptId)
            const totalIds = childIds.length ? childIds : [deptId]
            totalIds.forEach(id => allIds.add(id))
            return {
                dept_id: deptId,
                dept_name: String(dept.dept_name),
                target_amount: Number(dept.target_amount),
                totalIds,
            }
        })

        if (!allIds.size) return

        // 从 channelGroups 找自媒体1/3/4 的 channel_code
        const allChannels = channelGroups.value.flatMap(g => g.channels)
        const douyinCode = allChannels.find(c => c.channel_name.includes('自媒体1'))?.channel_code
        const t3Code = allChannels.find(c => c.channel_name.includes('自媒体3'))?.channel_code
        const t4Code = allChannels.find(c => c.channel_name.includes('自媒体4'))?.channel_code

        const deptIdsStr = Array.from(allIds).join(',')

        // 并发拉取：无渠道（总诊金/昨日）+ 各渠道（completed_performance_amount）
        const [perfRes, douyinRes, t3Res, t4Res] = await Promise.all([
            yejiStatsMulti({ dept_ids: deptIdsStr }) as any,
            douyinCode ? yejiStatsMulti({ dept_ids: deptIdsStr, channel_code: douyinCode }) as any : Promise.resolve(null),
            t3Code ? yejiStatsMulti({ dept_ids: deptIdsStr, channel_code: t3Code }) as any : Promise.resolve(null),
            t4Code ? yejiStatsMulti({ dept_ids: deptIdsStr, channel_code: t4Code }) as any : Promise.resolve(null),
        ])

        const getMonthTbl = (res: any) => (res?.tables ?? []).find((t: any) => String(t.label).includes('月')) ?? res?.tables?.[0]
        const getYdayTbl  = (res: any) => (res?.tables ?? []).find((t: any) => String(t.label).includes('昨')) ?? res?.tables?.[res?.tables?.length - 1]

        function buildMap(tbl: any, field: string): Map<number, number> {
            const m = new Map<number, number>()
            for (const r of tbl?.rows ?? []) m.set(Number(r.dept_id), Number(r[field] ?? 0))
            return m
        }

        const monthPerf  = buildMap(getMonthTbl(perfRes),   'performance_amount')
        const ydayPerf   = buildMap(getYdayTbl(perfRes),    'performance_amount')
        const douyinPerf = douyinRes ? buildMap(getMonthTbl(douyinRes), 'completed_performance_amount') : null
        const t3Perf     = t3Res     ? buildMap(getMonthTbl(t3Res),     'completed_performance_amount') : null
        const t4Perf     = t4Res     ? buildMap(getMonthTbl(t4Res),     'completed_performance_amount') : null

        const sumIds = (m: Map<number, number>, ids: number[]) => ids.reduce((s, id) => s + (m.get(id) ?? 0), 0)

        const today = new Date()
        const totalDays = daysInMonth(ym)
        const elapsed = today.getDate()

        const sections: TargetProgressSection[] = specs.map(spec => {
            const total     = sumIds(monthPerf, spec.totalIds)
            const yesterday = sumIds(ydayPerf,  spec.totalIds)

            const douyinAmt = douyinPerf ? sumIds(douyinPerf, spec.totalIds) : null
            const t3Amt     = t3Perf     ? sumIds(t3Perf,     spec.totalIds) : null
            const t4Amt     = t4Perf     ? sumIds(t4Perf,     spec.totalIds) : null
            // 推粉 = 自媒体3 + 自媒体4，有任一即显示
            const tuifenAmt = (t3Amt !== null || t4Amt !== null) ? (t3Amt ?? 0) + (t4Amt ?? 0) : null

            const targetProgress = Math.round(spec.target_amount * (elapsed / totalDays) * 100) / 100
            const completion = spec.target_amount > 0 ? total / spec.target_amount : null
            return {
                dept_id: spec.dept_id,
                dept_name: spec.dept_name,
                target_amount: spec.target_amount,
                total_amount: total,
                yesterday_amount: yesterday,
                douyin_amount: douyinAmt && douyinAmt > 0 ? douyinAmt : null,
                tuifen_amount: tuifenAmt && tuifenAmt > 0 ? tuifenAmt : null,
                target_progress: targetProgress,
                completion_rate: completion,
            }
        })

        // 取根部门名作为卡片标题前缀
        const rootName = treeRows[0]?.dept_name ?? ''
        const m = today.getMonth() + 1
        const d = today.getDate()
        targetProgressCard.value = {
            title: `${rootName}诊金-${m}.${d}`,
            sections,
        }
    } catch {
        // 静默失败，不影响主页面
    } finally {
        targetProgressLoading.value = false
    }
}

const channelFilterNote = computed(() => {
    for (const t of tables.value) {
        if (t.channel_filter_note) return t.channel_filter_note
    }
    return ''
})

const leaderboardVisibleTables = computed(() => {
    const list = leaderboardBlock.value?.leaderboards
    if (!list) return 0
    return list.filter((x) => x.rows.length > 0).length
})

const dateShortcuts = [
    {
        text: '昨天',
        value: () => {
            const d = new Date()
            d.setDate(d.getDate() - 1)
            return [d, d]
        },
    },
    {
        text: '最近七天',
        value: () => {
            const e = new Date()
            const s = new Date()
            s.setDate(s.getDate() - 6)
            return [s, e]
        },
    },
    {
        text: '本月',
        value: () => {
            const e = new Date()
            const s = new Date(e.getFullYear(), e.getMonth(), 1)
            return [s, e]
        },
    },
    {
        text: '今日',
        value: () => {
            const d = new Date()
            return [d, d]
        },
    },
    {
        text: '本周',
        value: () => {
            const e = new Date()
            const s = new Date()
            const day = s.getDay() || 7
            s.setDate(s.getDate() - (day - 1))
            return [s, e]
        },
    },
    {
        text: '上月',
        value: () => {
            const e0 = new Date()
            const s = new Date(e0.getFullYear(), e0.getMonth() - 1, 1)
            const e = new Date(e0.getFullYear(), e0.getMonth(), 0)
            return [s, e]
        },
    },
]

function applyDateShortcut(shortcut: (typeof dateShortcuts)[number]) {
    const pair = shortcut.value() as [Date, Date]
    customRange.value = [formatLocalYmd(pair[0]), formatLocalYmd(pair[1])]
    loadData()
}

async function loadDeptOptions() {
    deptOptionsLoading.value = true
    try {
        const res: DeptOption[] = await yejiStatsDeptOptions()
        deptOptions.value = (res || []).sort((a, b) => {
            const aIsCenter = a.name.includes('中心') ? -1 : 1
            const bIsCenter = b.name.includes('中心') ? -1 : 1
            if (aIsCenter !== bIsCenter) return aIsCenter - bIsCenter
            return a.id - b.id
        })
    } catch (_e) {
        // ignore
    } finally {
        deptOptionsLoading.value = false
    }
}

async function loadChannelOptions() {
    channelOptionsLoading.value = true
    try {
        const res: any = await yejiStatsChannelOptions()
        const groups: ChannelGroup[] = res?.groups || []
        channelGroups.value = groups
    } catch (_e) {
        // ignore
    } finally {
        channelOptionsLoading.value = false
    }
}

async function loadLeaderboard(range: { start: string; end: string }) {
    leaderboardsLoading.value = true
    try {
        const p: Record<string, any> = {
            start_date: range.start,
            end_date: range.end,
        }
        if (selectedDeptIds.value.length > 0) {
            p.dept_ids = selectedDeptIds.value.join(',')
        }
        if (selectedChannel.value) {
            p.channel_code = selectedChannel.value
        }
        const res: any = await yejiStatsLeaderboard(p as any)
        leaderboardBlock.value = {
            start_date: res.start_date,
            end_date: res.end_date,
            channel_code: res.channel_code || '',
            channel_name: res.channel_name || '',
            channel_filter_note: res.channel_filter_note || '',
            range_note: res.range_note || '',
            leaderboards: res.leaderboards || [],
        }
    } catch (_e) {
        leaderboardBlock.value = null
    } finally {
        leaderboardsLoading.value = false
    }
}

async function loadData() {
    loading.value = true
    leaderboardBlock.value = null
    try {
        const baseParams: Record<string, any> = {}
        if (selectedDeptIds.value.length > 0) {
            baseParams.dept_ids = selectedDeptIds.value.join(',')
        }
        if (selectedChannel.value) {
            baseParams.channel_code = selectedChannel.value
        }

        // 自定义日期 → 单表 overview 模式；否则 → 多表 multi
        if (customRange.value && customRange.value[0] && customRange.value[1]) {
            const [s, e] = customRange.value
            const params: Record<string, any> = { ...baseParams, start_date: s, end_date: e }
            const res: any = await yejiStatsOverview(params as any)
            tables.value = [
                {
                    label: s === e ? s : `${s} ~ ${e}`,
                    start_date: res.start_date,
                    end_date: res.end_date,
                    channel_code: res.channel_code || '',
                    channel_name: res.channel_name || '',
                    channel_group: res.channel_group || '',
                    channel_filter_note: res.channel_filter_note || '',
                    rows: res.rows || [],
                    total: res.total,
                },
            ]
            await loadLeaderboard({ start: res.start_date, end: res.end_date })
            return
        }

        const res: any = await yejiStatsMulti(baseParams as any)
        tables.value = (res?.tables || []).map((t: any) => ({
            label: t.label,
            start_date: t.start_date,
            end_date: t.end_date,
            channel_code: t.channel_code || '',
            channel_name: t.channel_name || '',
            channel_group: t.channel_group || '',
            channel_filter_note: t.channel_filter_note || '',
            rows: t.rows || [],
            total: t.total,
        }))
        const ymd = formatLocalYmd(new Date())
        await loadLeaderboard({ start: ymd, end: ymd })
    } catch (e: any) {
        ElMessage.error(e?.msg || e?.message || '加载失败')
    } finally {
        loading.value = false
    }
}

function handleReset() {
    selectedDeptIds.value = []
    customRange.value = null
    selectedChannel.value = ''
    loadData()
}

// 表标题：参考截图「【4月】各分部 自媒体1 数据」格式
function buildTableTitle(t: YejiTable): string {
    const channelLbl = t.channel_name ? ` · ${t.channel_name}` : ''
    return `${t.label}${channelLbl}`
}

// 表头：「{渠道名}业绩」（未选渠道时该列被 v-if 隐藏，因为它和「合计业绩」同值）
function buildCompletedColTitle(t: YejiTable): string {
    return t.channel_name ? `${t.channel_name}业绩` : '合计业绩'
}

// 通用：「{渠道名}{后缀}」，仅选渠道时使用
function buildChannelColTitle(t: YejiTable, suffix: string): string {
    return `${t.channel_name}${suffix}`
}

// ── 格式化 ───────────────────────────────
function formatInt(v: any) {
    if (v === null || v === undefined || v === '') return '0'
    return Number(v).toLocaleString('en-US')
}
function formatMoney(v: any) {
    if (v === null || v === undefined || v === '') return '0.0'
    return Number(v).toLocaleString('en-US', { minimumFractionDigits: 1, maximumFractionDigits: 1 })
}
function formatNumber(v: any) {
    if (v === null || v === undefined || v === '') return '—'
    return Number(v).toLocaleString('en-US', { minimumFractionDigits: 1, maximumFractionDigits: 1 })
}
function formatRoi(v: any) {
    if (v === null || v === undefined || v === '') return '—'
    return Number(v).toFixed(1)
}
function roiClass(v: any) {
    if (v === null || v === undefined || v === '') return ''
    const n = Number(v)
    if (n >= 1) return 'roi-good'
    if (n >= 0.8) return 'roi-mid'
    return 'roi-bad'
}
function formatAchievement(v: number | null): string {
    if (v === null) return '—'
    return (v * 100).toFixed(2) + '%'
}
function achievementClass(v: number | null): string {
    if (v === null) return ''
    if (v >= 1) return 'tp-good'
    if (v >= 0.8) return 'tp-mid'
    return 'tp-bad'
}
function formatMoneyW(v: number): string {
    if (v >= 10000) return (v / 10000).toFixed(1) + '万'
    return String(v)
}

/** 本地日历日 yyyy-mm-dd（排行榜「今日」、日期快捷与日期控件一致） */
function formatLocalYmd(d: Date): string {
    const y = d.getFullYear()
    const m = String(d.getMonth() + 1).padStart(2, '0')
    const day = String(d.getDate()).padStart(2, '0')
    return `${y}-${m}-${day}`
}

onMounted(async () => {
    await Promise.all([loadDeptOptions(), loadChannelOptions()])
    loadData()
    loadTargetProgress()
})
</script>

<style lang="scss" scoped>
.yeji-page {
    padding: 16px;
}

.filter-card {
    margin-bottom: 16px;
    border-radius: 12px;
    border: 1px solid var(--el-border-color-lighter);
    overflow: hidden;

    :deep(.el-card__body) {
        padding: 0;
    }
}

.filter-surface {
    padding: 18px 20px 16px;
    background: linear-gradient(180deg, var(--el-fill-color-blank) 0%, var(--el-fill-color-light) 100%);
}

.filter-row {
    &--top {
        display: flex;
        flex-wrap: wrap;
        align-items: flex-end;
        gap: 16px 20px;
    }
}

.filter-field {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    min-width: 0;

    .lbl {
        font-size: 12px;
        font-weight: 600;
        color: var(--el-text-color-secondary);
        letter-spacing: 0.02em;
    }

    &--wide {
        flex: 1 1 280px;
        min-width: 240px;
    }

    &--date-top {
        flex: 1 1 320px;
        min-width: 260px;
    }
}

.filter-select {
    width: 100%;

    &--channel {
        min-width: 220px;
        max-width: 320px;
    }

    &--dept {
        min-width: 280px;
    }
}

.filter-date-picker {
    width: 100%;
    max-width: 320px;
}

.filter-hint {
    margin: 14px 0 0;
    padding: 10px 12px;
    font-size: 12px;
    line-height: 1.55;
    color: var(--el-text-color-secondary);
    background: var(--el-fill-color);
    border-radius: 8px;
    border: 1px solid var(--el-border-color-lighter);
}

.filter-quick {
    margin-top: 14px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 14px;
}

.filter-quick__title {
    flex-shrink: 0;
    font-size: 12px;
    font-weight: 600;
    color: var(--el-text-color-regular);
}

.date-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.date-pill {
    appearance: none;
    margin: 0;
    border: 1px solid var(--el-border-color);
    background: var(--el-bg-color);
    color: var(--el-text-color-primary);
    font-size: 13px;
    font-weight: 500;
    padding: 7px 16px;
    border-radius: 999px;
    cursor: pointer;
    line-height: 1.35;
    transition:
        border-color 0.18s ease,
        background 0.18s ease,
        color 0.18s ease,
        box-shadow 0.18s ease,
        transform 0.12s ease;

    &:hover {
        border-color: var(--el-color-primary-light-5);
        color: var(--el-color-primary);
        background: var(--el-color-primary-light-9);
        box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
    }

    &:active {
        transform: scale(0.97);
    }

    &:focus-visible {
        outline: 2px solid var(--el-color-primary-light-5);
        outline-offset: 2px;
    }
}

.filter-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin-left: auto;
    flex-shrink: 0;
}

.filter-btn {
    padding: 10px 22px;
    font-weight: 600;
    letter-spacing: 0.02em;

    &__icon {
        margin-right: 6px;
        font-size: 16px;
    }

    &--query {
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);

        &:hover {
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
        }
    }

    &--reset {
        border: 1px solid var(--el-border-color);
        background: var(--el-bg-color);
        color: var(--el-text-color-regular);

        &:hover {
            border-color: var(--el-color-info-light-5);
            color: var(--el-color-primary);
            background: var(--el-fill-color-light);
        }

        &:disabled {
            opacity: 0.55;
        }
    }
}

.channel-opt-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    width: 100%;
    padding-right: 4px;
}

.opt-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.opt-count {
    flex-shrink: 0;
    font-size: 12px;
    color: var(--el-text-color-secondary);
}

.filter-alert {
    margin-bottom: 12px;
}

.tables-wrap {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(560px, 1fr));
    gap: 16px;
}

.leaderboards-wrap {
    margin-top: 20px;
    min-height: 48px;
}

.leaderboard-hint {
    margin: 0 0 12px;
    font-size: 13px;
    color: var(--el-text-color-primary);
    line-height: 1.6;

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

/* ── 目标进度卡片 ── */
.tp-wrap {
    min-height: 40px;
}

.tp-card {
    display: inline-block;
    border: 2px solid #e8b800;
    border-radius: 6px;
    overflow: hidden;
    font-size: 13px;
    background: #fff;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);

    &__title {
        background: #ffe600;
        color: #1f1f1f;
        font-weight: 700;
        font-size: 15px;
        text-align: center;
        padding: 8px 20px;
        letter-spacing: 1px;
    }

    &__body {
        display: flex;
        gap: 0;
    }
}

.tp-section {
    min-width: 200px;
    border-right: 1px solid #e8d800;

    &:last-child {
        border-right: none;
    }

    &__head {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 8px;
        background: #fff8c0;
        padding: 6px 12px;
        border-bottom: 1px solid #e8d800;
    }

    &__name {
        font-weight: 700;
        font-size: 13px;
        color: #333;
    }

    &__target {
        font-size: 13px;
        font-weight: 700;
        color: #b45309;
    }
}

.tp-table {
    width: 100%;
    border-collapse: collapse;

    .tp-lbl {
        padding: 5px 10px;
        color: #555;
        font-size: 12px;
        border-bottom: 1px solid #f0e860;
        white-space: nowrap;
    }

    .tp-val {
        padding: 5px 12px;
        font-weight: 600;
        text-align: right;
        border-bottom: 1px solid #f0e860;
        white-space: nowrap;
        color: #111;

        &--total {
            color: #b45309;
        }
    }

    tr:last-child td {
        border-bottom: none;
    }
}

.tp-good { color: #16a34a !important; font-weight: 700; }
.tp-mid  { color: #d97706 !important; font-weight: 700; }
.tp-bad  { color: #dc2626 !important; font-weight: 700; }

.leaderboard-sub {
    font-size: 13px;
    font-weight: 500;
}

.leaderboard-table {
    .th-sub {
        display: block;
        font-size: 11px;
        font-weight: 500;
        opacity: 0.85;
    }

    .col-rank {
        width: 52px;
        font-weight: 600;
    }

    .col-abbr {
        width: 48px;
    }

    .col-name {
        min-width: 72px;
        font-weight: 500;
    }
}

.leaderboard-empty {
    grid-column: 1 / -1;
}

.yeji-table__foot--left {
    text-align: left;
}

.empty-tip {
    grid-column: 1 / -1;
    background: #fff;
    border-radius: 6px;
    padding: 32px 0;
}

.yeji-table {
    background: #fff;
    border-radius: 6px;
    overflow: hidden;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
    border: 1px solid #e6e6e6;

    &__header {
        background: #ffe600; // 仿截图的黄色标题条
        color: #1f1f1f;
        font-weight: 700;
        font-size: 16px;
        text-align: center;
        padding: 10px 0;
        letter-spacing: 1px;
    }

    &__body {
        width: 100%;
        border-collapse: collapse;
        text-align: center;
        font-size: 13px;
        color: #333;

        thead th {
            background: #ffe600;
            color: #1f1f1f;
            font-weight: 600;
            padding: 8px 6px;
            border: 1px solid #d8d8d8;

            .col-info {
                margin-left: 4px;
                color: #6b7280;
                cursor: help;
                vertical-align: -2px;
                font-size: 13px;
            }
        }

        tbody td {
            padding: 8px 6px;
            border: 1px solid #e6e6e6;
            white-space: nowrap;
        }

        .col-dept {
            width: 80px;
            font-weight: 600;
            background: #fafafa;
        }

        .col-completed {
            color: #0d9488;
            font-weight: 600;
            background: #f0fdfa;
        }


        .total-row {
            font-weight: 700;
            background: #fff8d6;
        }

        .roi-good {
            color: #16a34a;
            font-weight: 600;
        }

        .roi-mid {
            color: #d97706;
            font-weight: 600;
        }

        .roi-bad {
            color: #dc2626;
            font-weight: 600;
        }
    }

    &__foot {
        padding: 6px 12px;
        font-size: 12px;
        color: var(--el-text-color-secondary);
        background: #fafafa;
        border-top: 1px solid #e6e6e6;
        text-align: right;
    }
}
</style>
