<template>
  <section class="report-page">
    <header class="panel report-toolbar">
      <div>
        <p class="section-kicker">M10-B · 可复算口径</p>
        <h3>经营统计报表</h3>
        <p>所有日期按各门店时区切分；净收入等于成功实收减成功退款。</p>
      </div>
      <div class="report-actions">
        <el-select v-model="storeId" placeholder="全部授权门店" clearable filterable>
          <el-option v-for="store in stores" :key="store.id" :label="store.name" :value="store.id" />
        </el-select>
        <el-date-picker v-model="range" type="daterange" unlink-panels range-separator="至"
          start-placeholder="开始日期" end-placeholder="结束日期" :clearable="false" />
        <el-button-group>
          <el-button @click="setPreset(1)">今日</el-button>
          <el-button @click="setPreset(7)">近 7 日</el-button>
        </el-button-group>
        <el-button type="primary" :icon="RefreshCw" :loading="loading" @click="load">查询</el-button>
        <el-button :icon="Download" :loading="exporting" @click="exportCsv">导出</el-button>
        <el-button v-if="canRebuild" :icon="RotateCcw" :loading="rebuilding" @click="rebuild">重算日汇总</el-button>
      </div>
    </header>

    <el-alert v-if="errorMessage" type="error" :title="errorMessage" show-icon :closable="false" />
    <template v-if="report">
      <section class="report-metrics">
        <article><span>总净收入</span><strong>{{ money(report.summary.totalNetCents) }}</strong><small>房费 {{ money(report.summary.roomNetCents) }} · 商品 {{ money(report.summary.productNetCents) }}</small></article>
        <article><span>成功退款</span><strong>{{ money(report.summary.roomRefundCents + report.summary.productRefundCents) }}</strong><small>收入均已扣减退款</small></article>
        <article><span>订单 / 下单人数</span><strong>{{ report.summary.orderCount }} / {{ report.summary.customerCount }}</strong><small>{{ report.scope.storeCount }} 家门店</small></article>
        <article><span>实际使用时长</span><strong>{{ duration(report.summary.usedMinutes) }}</strong><small>利用率 {{ percent(report.summary.utilizationBasisPoints) }}</small></article>
        <article><span>保洁成本</span><strong>{{ money(report.summary.cleaningCostCents) }}</strong><small>贡献额 {{ money(report.summary.contributionCents) }}</small></article>
      </section>

      <section class="panel reconciliation-card">
        <div>
          <p class="section-kicker">日汇总与明细复算</p>
          <h3>{{ reconciliationText }}</h3>
          <p>明细复算 {{ report.reconciliation.expectedRows }} 行，日汇总 {{ report.reconciliation.persistedRows }} 行，差异 {{ report.reconciliation.mismatchRows }} 行。</p>
        </div>
        <el-tag :type="report.reconciliation.status === 'MATCHED' ? 'success' : report.reconciliation.status === 'MISMATCH' ? 'danger' : 'warning'">
          {{ report.reconciliation.status }}
        </el-tag>
      </section>

      <section class="report-grid">
        <article class="panel">
          <div class="section-heading"><div><p class="section-kicker">支付渠道</p><h3>净收入拆分</h3></div></div>
          <div class="channel-grid">
            <div v-for="channel in channels" :key="channel.key"><span>{{ channel.label }}</span><strong>{{ money(report.summary.channels[channel.key]) }}</strong></div>
          </div>
        </article>
        <article class="panel">
          <div class="section-heading"><div><p class="section-kicker">明细来源</p><h3>复算记录数</h3></div></div>
          <div class="channel-grid">
            <div v-for="(value, key) in report.detailCounts" :key="key"><span>{{ detailLabel(key) }}</span><strong>{{ value }}</strong></div>
          </div>
        </article>
      </section>

      <section class="panel report-table">
        <div class="section-heading"><div><p class="section-kicker">逐店逐日</p><h3>经营明细</h3></div><span>{{ report.metricVersion }}</span></div>
        <el-table :data="report.daily" stripe max-height="560">
          <el-table-column prop="date" label="日期" width="112" fixed />
          <el-table-column prop="storeName" label="门店" min-width="150" fixed />
          <el-table-column label="净收入" width="120" align="right"><template #default="{ row }">{{ money(row.totalNetCents) }}</template></el-table-column>
          <el-table-column label="商品收入" width="120" align="right"><template #default="{ row }">{{ money(row.productNetCents) }}</template></el-table-column>
          <el-table-column label="保洁成本" width="120" align="right"><template #default="{ row }">{{ money(row.cleaningCostCents) }}</template></el-table-column>
          <el-table-column prop="orderCount" label="订单" width="78" align="right" />
          <el-table-column prop="customerCount" label="人数" width="78" align="right" />
          <el-table-column label="使用时长" width="110" align="right"><template #default="{ row }">{{ duration(row.usedMinutes) }}</template></el-table-column>
          <el-table-column label="利用率" width="100" align="right"><template #default="{ row }">{{ percent(row.utilizationBasisPoints) }}</template></el-table-column>
          <el-table-column prop="timezone" label="时区" width="140" />
        </el-table>
      </section>
    </template>
  </section>
</template>

<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
import { Download, RefreshCw, RotateCcw } from '@lucide/vue';
import { ElMessage } from 'element-plus';
import {
  ApiError, downloadBusinessReport, getBusinessReport, listManagedStores,
  rebuildBusinessReport, type ApiSession
} from '../api';
import { money } from '../format';
import { adminSessionState } from '../session';
import type { BusinessReport, BusinessReportChannel, ManagedStore } from '../types';

const props = defineProps<{ session: ApiSession }>();
const stores = ref<ManagedStore[]>([]);
const storeId = ref('');
const range = ref<[Date, Date]>(presetRange(7));
const report = ref<BusinessReport | null>(null);
const loading = ref(false);
const exporting = ref(false);
const rebuilding = ref(false);
const errorMessage = ref('');
const canRebuild = computed(() => adminSessionState.access.roles.includes('PLATFORM_ADMIN')
  || adminSessionState.access.capabilities.includes('tenant.manage')
  || adminSessionState.access.capabilities.includes('report.manage'));
const channels: Array<{ key: BusinessReportChannel; label: string }> = [
  { key: 'WECHAT', label: '微信' }, { key: 'BALANCE', label: '余额' },
  { key: 'PACKAGE', label: '套餐' }, { key: 'GROUP_BUY', label: '团购平台' },
  { key: 'OTHER', label: '其他' }
];
const reconciliationText = computed(() => ({
  MATCHED: '日汇总与明细一致', NOT_AGGREGATED: '尚未生成日汇总', MISMATCH: '日汇总需要重算'
})[report.value?.reconciliation.status ?? 'NOT_AGGREGATED']);

function requestInput() {
  return { storeId: storeId.value || undefined, from: dateKey(range.value[0]), to: dateKey(range.value[1]) };
}

async function load() {
  loading.value = true; errorMessage.value = '';
  try { report.value = await getBusinessReport(props.session, requestInput()); }
  catch (error) { report.value = null; capture(error); }
  finally { loading.value = false; }
}

async function rebuild() {
  rebuilding.value = true;
  try {
    const result = await rebuildBusinessReport(props.session, requestInput());
    ElMessage.success(`已加入 ${result.queued} 个日汇总任务；Worker 完成后刷新即可复核。`);
  } catch (error) { capture(error); }
  finally { rebuilding.value = false; }
}

async function exportCsv() {
  exporting.value = true;
  try {
    const blob = await downloadBusinessReport(props.session, requestInput());
    const url = URL.createObjectURL(blob); const anchor = document.createElement('a');
    anchor.href = url; anchor.download = `business-report-${dateKey(range.value[0])}-${dateKey(range.value[1])}.csv`;
    anchor.click(); URL.revokeObjectURL(url);
  } catch (error) { capture(error); }
  finally { exporting.value = false; }
}

function setPreset(days: number) { range.value = presetRange(days); void load(); }
function presetRange(days: number): [Date, Date] { const to = new Date(); const from = new Date(to); from.setDate(from.getDate() - days + 1); return [from, to]; }
function dateKey(value: Date) { const year = value.getFullYear(); const month = String(value.getMonth() + 1).padStart(2, '0'); const day = String(value.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; }
function duration(minutes: number) { return minutes >= 60 ? `${Math.floor(minutes / 60)} 小时 ${minutes % 60} 分` : `${minutes} 分钟`; }
function percent(basisPoints: number) { return `${(basisPoints / 100).toFixed(2)}%`; }
function detailLabel(key: string) { return ({ payments: '房费支付', refunds: '房费退款', productPayments: '商品支付', productRefunds: '商品退款', orders: '房间订单', cleaningEntries: '保洁成本/冲正' } as Record<string, string>)[key] ?? key; }
function capture(error: unknown) { errorMessage.value = error instanceof ApiError ? `${error.message}（${error.code}）` : error instanceof Error ? error.message : '报表请求失败'; }

onMounted(async () => {
  try { stores.value = await listManagedStores(props.session); await load(); }
  catch (error) { capture(error); }
});
</script>

<style scoped>
.report-page { display: grid; gap: 18px; }
.report-toolbar { display: flex; justify-content: space-between; gap: 20px; align-items: flex-end; padding: 22px; }
.report-toolbar h3, .reconciliation-card h3 { margin: 4px 0; }
.report-toolbar p, .reconciliation-card p { margin: 0; color: var(--text-muted); }
.report-actions { display: flex; flex-wrap: wrap; gap: 10px; justify-content: flex-end; }
.report-actions > .el-select { width: 190px; }
.report-metrics { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 14px; }
.report-metrics article { background: var(--surface); border: 1px solid var(--border); border-radius: 16px; padding: 18px; display: grid; gap: 7px; }
.report-metrics span, .report-metrics small { color: var(--text-muted); }
.report-metrics strong { font-size: 24px; }
.reconciliation-card { display: flex; justify-content: space-between; align-items: center; padding: 20px; }
.report-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.report-grid > article, .report-table { padding: 20px; }
.channel-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; }
.channel-grid > div { background: var(--surface-soft); border-radius: 12px; padding: 14px; display: grid; gap: 6px; }
.channel-grid span { color: var(--text-muted); font-size: 13px; }
@media (max-width: 1180px) { .report-toolbar { align-items: stretch; flex-direction: column; } .report-actions { justify-content: flex-start; } .report-metrics { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 720px) { .report-metrics, .report-grid { grid-template-columns: 1fr; } .report-actions > * { width: 100% !important; } }
</style>
