<template>
    <div class="revisit-rate-page">
        <el-card class="!border-none" shadow="never">
            <el-form :inline="true" class="rate-filter-form">
                <el-form-item label="统计月份">
                    <el-date-picker
                        v-model="month"
                        type="month"
                        value-format="YYYY-MM"
                        placeholder="选择月份"
                        :clearable="false"
                        :disabled-date="disableFutureMonth"
                        style="width: 160px"
                        @change="loadData"
                    />
                </el-form-item>
                <el-form-item label="部门">
                    <el-tree-select
                        v-model="deptId"
                        :data="deptTreeOptions"
                        placeholder="全部部门"
                        clearable
                        filterable
                        check-strictly
                        node-key="id"
                        :default-expand-all="true"
                        :props="deptTreeProps"
                        style="width: 220px"
                        @change="loadData"
                    />
                </el-form-item>
                <el-form-item>
                    <el-button type="primary" :loading="loading" @click="loadData">查询</el-button>
                    <el-button :disabled="loading" @click="handleReset">重置</el-button>
                </el-form-item>
                <el-form-item>
                    <el-popover placement="bottom-start" :width="500" trigger="hover">
                        <template #reference>
                            <span class="rate-caliber-trigger">
                                <el-icon><InfoFilled /></el-icon>
                                统计口径
                            </span>
                        </template>
                        <div class="rate-caliber">
                            <p>
                                <b>当月被指派总数</b>：当月内诊单被指派给医助（按指派操作时间落月，<b>剔除勾选「继承」的指派</b>)的诊单数，按「医助 × 诊单」去重；部门行 / 合计行按诊单去重。
                            </p>
                            <p>
                                <b>诊次（第 N 次下单）</b>：患者（诊单）名下计入业绩的业务订单（剔除已取消 / 拒收 / 退款）按下单时间升序的全局序号，<b>跨月累计不重置</b>——如 5 月指派后旗下成交 4 单为二诊~五诊，下月再成交即为六诊。
                            </p>
                            <p>
                                <b>当月 N 诊单数</b>：当月内下单且诊次为 N 的订单数，归属下单时点<b>持有该患者的医助</b>（指派可在往月；释放后不再归属；「继承」指派会转移持有人但不计被指派数）。
                            </p>
                            <p>
                                <b>当月 N 诊接诊率</b> = 当月 N 诊单数 ÷ 当月被指派总数。往月指派、当月成交会推高分子，比率可能超过 100%；医助当月无新指派但旗下有成交时，被指派数为 0、比率显示「—」。
                            </p>
                            <p>
                                医助按人事部门归组；选定部门时含其组织下级。
                            </p>
                        </div>
                    </el-popover>
                </el-form-item>
            </el-form>
        </el-card>

        <div class="rate-kpi-grid">
            <div
                v-for="card in summaryCards"
                :key="card.key"
                class="rate-kpi-card"
                :class="{ 'is-clickable': card.clickable }"
                @click="card.clickable && card.onClick && card.onClick()"
            >
                <div class="rate-kpi-label">{{ card.label }}</div>
                <div class="rate-kpi-value">{{ card.value }}</div>
                <div v-if="card.sub" class="rate-kpi-sub">{{ card.sub }}</div>
            </div>
        </div>

        <el-card class="!border-none mt-4" shadow="never">
            <template #header>
                <div class="rate-card-header">
                    <span>部门 · 医助明细（{{ monthText }}）</span>
                    <span class="rate-card-hint">点击「被指派数 / N诊单数」可查看具体诊单与订单；底栏合计的被指派数按诊单去重</span>
                </div>
            </template>
            <el-table
                v-loading="loading"
                :data="rows"
                size="small"
                border
                row-key="row_key"
                :tree-props="{ children: 'children' }"
                :default-expand-all="true"
                show-summary
                :summary-method="getSummaries"
            >
                <el-table-column label="部门 / 医助" min-width="200" fixed>
                    <template #default="{ row }">
                        <span v-if="row.is_dept" class="rate-dept-cell">
                            {{ row.dept_name }}
                            <span class="rate-dept-count">{{ row.assistant_count }} 人</span>
                        </span>
                        <span v-else>{{ row.assistant_name }}</span>
                    </template>
                </el-table-column>
                <el-table-column prop="assigned_count" label="当月被指派数" min-width="110" align="right">
                    <template #default="{ row }">
                        <el-link
                            v-if="canViewAssignLines && row.assigned_count > 0"
                            type="primary"
                            :underline="false"
                            @click="openAssignDetail(row)"
                        >
                            {{ row.assigned_count }}
                        </el-link>
                        <span v-else>{{ row.assigned_count }}</span>
                    </template>
                </el-table-column>
                <template v-for="slot in visitSlots" :key="slot">
                    <el-table-column
                        :prop="`visit${slot}_count`"
                        :label="`${slotLabel(slot)}单数`"
                        min-width="96"
                        align="right"
                    >
                        <template #header>
                            <span>{{ slotLabel(slot) }}单数</span>
                            <el-tooltip
                                effect="dark"
                                placement="top"
                                :content="`当月内下单、诊次为第 ${slot} 次的订单数（诊次跨月累计；归属下单时点持有患者的医助）`"
                            >
                                <el-icon class="rate-th-hint"><InfoFilled /></el-icon>
                            </el-tooltip>
                        </template>
                        <template #default="{ row }">
                            <el-link
                                v-if="canViewOrderLines && row[`visit${slot}_count`] > 0"
                                type="primary"
                                :underline="false"
                                @click="openOrderDetail(slot, row)"
                            >
                                {{ row[`visit${slot}_count`] }}
                            </el-link>
                            <span v-else>{{ row[`visit${slot}_count`] }}</span>
                        </template>
                    </el-table-column>
                    <el-table-column
                        :prop="`visit${slot}_rate`"
                        :label="`${slotLabel(slot)}接诊率`"
                        min-width="96"
                        align="right"
                    >
                        <template #default="{ row }">{{ formatRate(row[`visit${slot}_rate`]) }}</template>
                    </el-table-column>
                </template>
            </el-table>
        </el-card>

        <!-- 下钻明细 -->
        <el-dialog
            v-model="detailVisible"
            :title="detailTitle"
            width="980px"
            top="6vh"
            destroy-on-close
        >
            <el-table
                v-loading="detailLoading"
                :data="detailRows"
                size="small"
                border
                stripe
                max-height="60vh"
            >
                <template v-if="detailType === 'assign'">
                    <el-table-column prop="diagnosis_id" label="诊单ID" width="90" />
                    <el-table-column prop="patient_name" label="患者" min-width="100">
                        <template #default="{ row }">
                            <el-link
                                v-if="canViewPatientDetail && row.diagnosis_id"
                                type="primary"
                                :underline="false"
                                @click="openPatientDetail(row.diagnosis_id)"
                            >
                                {{ row.patient_name || `诊单#${row.diagnosis_id}` }}
                            </el-link>
                            <span v-else>{{ row.patient_name || '—' }}</span>
                        </template>
                    </el-table-column>
                    <el-table-column prop="patient_phone" label="联系电话" min-width="120">
                        <template #default="{ row }">{{ row.patient_phone || '—' }}</template>
                    </el-table-column>
                    <el-table-column prop="assistant_names" label="被指派医助" min-width="140" show-overflow-tooltip />
                    <el-table-column prop="assign_count" label="当月指派次数" width="110" align="right" />
                    <el-table-column prop="last_assign_time_text" label="最近指派时间" min-width="160" />
                </template>
                <template v-else>
                    <el-table-column prop="order_no" label="订单号" min-width="180" show-overflow-tooltip>
                        <template #default="{ row }">
                            <el-link
                                v-if="canViewOrderDetail && row.order_id"
                                type="primary"
                                :underline="false"
                                @click="openOrderInfo(row.order_id)"
                            >
                                {{ row.order_no || `#${row.order_id}` }}
                            </el-link>
                            <span v-else>{{ row.order_no || `#${row.order_id}` }}</span>
                        </template>
                    </el-table-column>
                    <el-table-column prop="diagnosis_id" label="诊单ID" width="90" />
                    <el-table-column prop="patient_name" label="患者" min-width="100">
                        <template #default="{ row }">
                            <el-link
                                v-if="canViewPatientDetail && row.diagnosis_id"
                                type="primary"
                                :underline="false"
                                @click="openPatientDetail(row.diagnosis_id)"
                            >
                                {{ row.patient_name || `诊单#${row.diagnosis_id}` }}
                            </el-link>
                            <span v-else>{{ row.patient_name || '—' }}</span>
                        </template>
                    </el-table-column>
                    <el-table-column prop="amount" label="金额" width="100" align="right">
                        <template #default="{ row }">¥ {{ row.amount }}</template>
                    </el-table-column>
                    <el-table-column prop="create_time_text" label="下单时间" min-width="160" />
                    <el-table-column prop="assistant_name" label="持有医助" min-width="100" />
                    <el-table-column prop="creator_name" label="订单创建人" min-width="100" />
                </template>
            </el-table>
            <div class="rate-detail-footer">共 {{ detailRows.length }} 条</div>
        </el-dialog>

        <!-- 订单详情抽屉（共享组件，与处方订单列表详情一致；只读） -->
        <order-detail-drawer ref="orderDetailRef" readonly append-to-body />

        <!-- 诊单（患者）详情：编辑页只读模式 -->
        <diagnosis-edit-popup ref="diagnosisEditRef" />
    </div>
</template>

<script setup lang="ts" name="revisitRateStatsPage">
import { computed, defineAsyncComponent, onMounted, ref } from 'vue'
import { InfoFilled } from '@element-plus/icons-vue'

import {
    revisitRateAssignLines,
    revisitRateDeptOptions,
    revisitRateOverview,
    revisitRateVisitOrderLines
} from '@/api/stats'
import { hasPermission } from '@/utils/perm'

/** 业务订单详情抽屉（共享组件，readonly 模式，与 order_list.vue 详情同源） */
const OrderDetailDrawer = defineAsyncComponent(
    () => import('@/views/consumer/prescription/components/PrescriptionOrderDetailDrawer.vue')
)
/** 诊单编辑弹窗（只读打开） */
const DiagnosisEditPopup = defineAsyncComponent(() => import('@/views/tcm/diagnosis/edit.vue'))

interface MetricPack extends Record<string, any> {
    assigned_count: number
}

interface StatsRow extends MetricPack {
    row_key: string
    is_dept: 0 | 1
    dept_id: number
    dept_name: string
    assistant_id?: number
    assistant_name?: string
    assistant_count?: number
    children?: StatsRow[]
}

interface DeptTreeNode {
    id: number
    name: string
    pid: number
    children?: DeptTreeNode[]
}

const canViewAssignLines = hasPermission(['stats.revisitRate/assignLines'])
const canViewOrderLines = hasPermission(['stats.revisitRate/visitOrderLines'])
const canViewOrderDetail = hasPermission(['tcm.prescriptionOrder/detail'])
const canViewPatientDetail = hasPermission(['tcm.diagnosis/detail'])

/** 接口动态返回的诊次分档（最少 2~4，按数据扩展到五诊、六诊…） */
const visitSlots = ref<number[]>([2, 3, 4])

const cnDigits = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
const slotLabel = (slot: number) => {
    if (slot >= 2 && slot <= 10) {
        return `${cnDigits[slot]}诊`
    }
    if (slot > 10 && slot < 20) {
        return `十${cnDigits[slot - 10]}诊`
    }
    return `${slot}诊`
}

const initNow = new Date()
const currentMonth = `${initNow.getFullYear()}-${String(initNow.getMonth() + 1).padStart(2, '0')}`
const month = ref<string>(currentMonth)
const deptId = ref<number | undefined>(undefined)
const loading = ref(false)
const rows = ref<StatsRow[]>([])
const total = ref<MetricPack | null>(null)

const deptTreeOptions = ref<DeptTreeNode[]>([])
const deptTreeProps = { value: 'id', label: 'name', children: 'children' }

const monthText = computed(() => {
    const [y, m] = month.value.split('-')
    return y && m ? `${y}年${Number(m)}月` : month.value
})

const formatRate = (rate: number | null | undefined) =>
    rate === null || rate === undefined ? '—' : `${rate}%`

const baseQuery = () => ({
    month: month.value,
    dept_ids: deptId.value ? String(deptId.value) : ''
})

interface SummaryCard {
    key: string
    label: string
    value: string
    sub: string
    clickable: boolean
    onClick?: () => void
}

const summaryCards = computed<SummaryCard[]>(() => {
    const t = total.value
    const cards: SummaryCard[] = [
        {
            key: 'assigned',
            label: '当月被指派总数',
            value: t ? String(t.assigned_count) : '—',
            sub: '',
            clickable: !!(canViewAssignLines && t && t.assigned_count > 0),
            onClick: () => openAssignDetail(null)
        }
    ]
    for (const slot of visitSlots.value) {
        const cnt = t ? t[`visit${slot}_count`] : null
        const rate = t ? t[`visit${slot}_rate`] : null
        cards.push({
            key: `visit${slot}`,
            label: `当月${slotLabel(slot)}接诊率`,
            value: t ? formatRate(rate) : '—',
            sub: t ? `${slotLabel(slot)}下单 ${cnt} 单` : '',
            clickable: !!(canViewOrderLines && cnt > 0),
            onClick: () => openOrderDetail(slot, null)
        })
    }
    return cards
})

/** 底栏合计：直接展示后端按诊单去重后的合计，不做各行求和 */
const getSummaries = ({ columns }: { columns: any[] }) => {
    const t = total.value
    return columns.map((col, index) => {
        if (index === 0) {
            return '合计'
        }
        if (!t) {
            return ''
        }
        const prop = String(col.property || '')
        if (prop === 'assigned_count') {
            return String(t.assigned_count)
        }
        if (/^visit\d+_count$/.test(prop)) {
            return String(t[prop] ?? '')
        }
        if (/^visit\d+_rate$/.test(prop)) {
            return formatRate(t[prop])
        }
        return ''
    })
}

const disableFutureMonth = (date: Date) => {
    const now = new Date()
    return date.getFullYear() * 12 + date.getMonth() > now.getFullYear() * 12 + now.getMonth()
}

const loadData = async () => {
    loading.value = true
    try {
        const res = await revisitRateOverview(baseQuery())
        rows.value = res?.rows ?? []
        total.value = res?.total ?? null
        if (Array.isArray(res?.slots) && res.slots.length) {
            visitSlots.value = res.slots.map((s: any) => Number(s)).filter((s: number) => s >= 2)
        }
        if (res?.month) {
            month.value = res.month
        }
    } finally {
        loading.value = false
    }
}

const buildDeptTree = (flat: Array<{ id: number; pid: number; name: string }>): DeptTreeNode[] => {
    const map = new Map<number, DeptTreeNode>()
    for (const d of flat) {
        map.set(d.id, { ...d, children: [] })
    }
    const roots: DeptTreeNode[] = []
    for (const d of flat) {
        const node = map.get(d.id)!
        if (d.pid > 0 && map.has(d.pid)) {
            map.get(d.pid)!.children!.push(node)
        } else {
            roots.push(node)
        }
    }
    const strip = (n: DeptTreeNode) => {
        if (n.children?.length) {
            n.children.forEach(strip)
        } else {
            delete n.children
        }
    }
    roots.forEach(strip)
    return roots
}

const loadDeptOptions = async () => {
    try {
        const res = await revisitRateDeptOptions()
        deptTreeOptions.value = buildDeptTree(res?.rows ?? [])
    } catch {
        deptTreeOptions.value = []
    }
}

// ── 下钻明细 ──────────────────────────────────────────
const detailVisible = ref(false)
const detailType = ref<'assign' | 'orders'>('assign')
const detailTitle = ref('')
const detailLoading = ref(false)
const detailRows = ref<any[]>([])

/** row 为 null 时表示合计（当前部门筛选范围） */
const rowScope = (row: StatsRow | null): { assistant_id?: number; dept_id?: number; label: string } => {
    if (!row) {
        return { label: '合计' }
    }
    if (row.is_dept) {
        return { dept_id: row.dept_id, label: row.dept_name }
    }
    return { assistant_id: row.assistant_id, label: row.assistant_name || '' }
}

const openAssignDetail = async (row: StatsRow | null) => {
    if (!canViewAssignLines) {
        return
    }
    const scope = rowScope(row)
    detailType.value = 'assign'
    detailTitle.value = `${scope.label} · 被指派明细（${monthText.value}）`
    detailVisible.value = true
    detailLoading.value = true
    detailRows.value = []
    try {
        const res = await revisitRateAssignLines({
            ...baseQuery(),
            assistant_id: scope.assistant_id,
            dept_id: scope.dept_id
        })
        detailRows.value = res?.rows ?? []
    } finally {
        detailLoading.value = false
    }
}

const openOrderDetail = async (slot: number, row: StatsRow | null) => {
    if (!canViewOrderLines) {
        return
    }
    const scope = rowScope(row)
    detailType.value = 'orders'
    detailTitle.value = `${scope.label} · ${slotLabel(slot)}订单明细（${monthText.value}）`
    detailVisible.value = true
    detailLoading.value = true
    detailRows.value = []
    try {
        const res = await revisitRateVisitOrderLines({
            ...baseQuery(),
            slot,
            assistant_id: scope.assistant_id,
            dept_id: scope.dept_id
        })
        detailRows.value = res?.rows ?? []
    } finally {
        detailLoading.value = false
    }
}

// ── 订单详情（复用处方订单列表的详情抽屉） ──────────────
const orderDetailRef = ref<{ open: (id: number) => void } | null>(null)

const openOrderInfo = (orderId: number) => {
    if (!canViewOrderDetail || !orderId) {
        return
    }
    orderDetailRef.value?.open(orderId)
}

// ── 患者（诊单）详情：诊单编辑页只读打开 ────────────────
const diagnosisEditRef = ref<{ openViewOnly: (id: number) => void } | null>(null)

const openPatientDetail = (diagnosisId: number) => {
    if (!canViewPatientDetail || !diagnosisId) {
        return
    }
    diagnosisEditRef.value?.openViewOnly(diagnosisId)
}

const handleReset = () => {
    month.value = currentMonth
    deptId.value = undefined
    loadData()
}

onMounted(() => {
    loadDeptOptions()
    loadData()
})
</script>

<style lang="scss" scoped>
.revisit-rate-page {
    .rate-filter-form {
        :deep(.el-form-item) {
            margin-bottom: 0;
        }
    }

    .rate-caliber-trigger {
        display: inline-flex;
        align-items: center;
        gap: 4px;
        color: var(--el-text-color-secondary);
        font-size: 13px;
        cursor: help;
    }

    .rate-kpi-grid {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
        gap: 12px;
        margin-top: 16px;
    }

    .rate-kpi-card {
        background: var(--el-bg-color);
        border-radius: 8px;
        padding: 16px 20px;

        &.is-clickable {
            cursor: pointer;
            transition: box-shadow 0.15s ease;

            &:hover {
                box-shadow: var(--el-box-shadow-light);
            }
        }

        .rate-kpi-label {
            color: var(--el-text-color-secondary);
            font-size: 13px;
        }

        .rate-kpi-value {
            margin-top: 6px;
            font-size: 26px;
            font-weight: 600;
            color: var(--el-text-color-primary);
        }

        .rate-kpi-sub {
            margin-top: 2px;
            font-size: 12px;
            color: var(--el-text-color-secondary);
        }
    }

    .rate-card-header {
        display: flex;
        align-items: baseline;
        gap: 10px;

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

    .rate-dept-cell {
        font-weight: 600;

        .rate-dept-count {
            margin-left: 6px;
            font-weight: 400;
            font-size: 12px;
            color: var(--el-text-color-secondary);
        }
    }

    .rate-th-hint {
        margin-left: 2px;
        vertical-align: -2px;
        color: var(--el-text-color-secondary);
        cursor: help;
    }
}

.rate-detail-footer {
    margin-top: 10px;
    text-align: right;
    font-size: 12px;
    color: var(--el-text-color-secondary);
}

.rate-caliber {
    font-size: 13px;
    line-height: 1.7;
    color: var(--el-text-color-regular);

    p + p {
        margin-top: 6px;
    }
}
</style>
