<script lang="ts" setup>
import {
  computed,
  reactive,
  ref,
  watch } from 'vue';

import { Page } from '@vben/common-ui';
import { useAccessStore } from '@vben/stores';

import {
  Button,
  Card,
  Input,
  message,
  Modal,
  Space,
  Table,
} from 'antdv-next';

import {
  confirmImport,
  deductMoney,
  exprotBank,
  getBankStatistics,
  pageBank,
  sendMoney,
  transferMoney,
  } from '#/api/legacy/operate';
import AccountInput from '#/components/account-input.vue';
import { formatDate,
  getAllowedSysOrigins } from '#/views/system/shared';

import UserBankCreateModal from './components/user-bank-create-modal.vue';
import UserBankRunningWaterModal from './components/user-bank-running-water-modal.vue';
import UserProfileLink from './components/user-profile-link.vue';

defineOptions({ name: 'OperateUserBankBalance' });

const accessStore = useAccessStore();
const sysOriginOptions = computed(() => {
  const options = getAllowedSysOrigins(accessStore.accessCodes || []);
  return options.length > 0 ? options : getAllowedSysOrigins([]);
});

const loading = ref(false);
const loadMoreLoading = ref(false);
const exportLoading = ref(false);
const statisticsLoading = ref(false);
const notData = ref(false);
const list = ref<Array<Record<string, any>>>([]);
const createOpen = ref(false);
const runningWaterOpen = ref(false);
const importOpen = ref(false);
const importLoading = ref(false);
const actionModalOpen = ref(false);
const transferOpen = ref(false);
const actionType = ref<'deduct' | 'send'>('send');
const activeRow = ref<null | Record<string, any>>(null);
const importInput = ref<HTMLInputElement | null>(null);

const query = reactive({
  lastId: '',
  limit: 20,
  pageNo: 1,
  sortField: '',
  sortOrder: '',
  sysOrigin: '',
  userId: '',
});

const statistics = reactive({
  totalBalance: 0,
  totalConsumptionPoints: 0,
  totalEarnPoints: 0,
});

const sortableAmountKeys = new Set(['balance', 'consumptionPoints', 'earnPoints']);

type BankSortOrder = 'ascend' | 'descend';

const isSortActive = computed(() => {
  return Boolean(query.sortField && query.sortOrder);
});

const actionForm = reactive({
  quantity: '',
  remark: '',
  sysOrigin: '',
  userId: '',
});

const transferForm = reactive({
  acceptUserId: '',
  quantity: '',
  remark: '',
  sysOrigin: '',
  userId: '',
});

const columns = computed(() => [
  { dataIndex: 'index', key: 'index', title: 'No', width: 70 },
  { dataIndex: 'sysOrigin', key: 'sysOrigin', title: '系统', width: 90 },
  { dataIndex: 'userProfile', key: 'userProfile', title: '用户', width: 300 },
  {
    align: 'right' as const,
    dataIndex: 'earnPoints',
    key: 'earnPoints',
    sorter: true,
    sortOrder: getSortOrder('earnPoints'),
    title: '获得总额',
    width: 120,
  },
  {
    align: 'right' as const,
    dataIndex: 'consumptionPoints',
    key: 'consumptionPoints',
    sorter: true,
    sortOrder: getSortOrder('consumptionPoints'),
    title: '消费总额',
    width: 120,
  },
  {
    align: 'right' as const,
    dataIndex: 'balance',
    key: 'balance',
    sorter: true,
    sortOrder: getSortOrder('balance'),
    title: '余额',
    width: 120,
  },
  { dataIndex: 'createTime', key: 'createTime', title: '创建时间', width: 180 },
  { dataIndex: 'updateTime', key: 'updateTime', title: '修改时间', width: 180 },
  { dataIndex: 'actions', key: 'actions', title: '操作', width: 260, fixed: 'right' as const },
]);

function isBankSortOrder(value: string): value is BankSortOrder {
  return value === 'ascend' || value === 'descend';
}

function getSortOrder(field: string) {
  return query.sortField === field && isBankSortOrder(query.sortOrder)
    ? query.sortOrder
    : undefined;
}

function formatAmount(value: any) {
  const rawValue = String(value ?? '0').replaceAll(',', '');
  if (!rawValue || rawValue === 'null' || rawValue === 'undefined') {
    return '0';
  }
  const [integerPart = '0', decimalPart = ''] = rawValue.split('.');
  const isNegative = integerPart.startsWith('-');
  const unsignedInteger = isNegative ? integerPart.slice(1) : integerPart;
  const formattedInteger =
    unsignedInteger.replaceAll(/\B(?=(\d{3})+(?!\d))/g, ',') || '0';
  const trimmedDecimal = decimalPart.replaceAll(/0+$/g, '');
  return `${isNegative ? '-' : ''}${formattedInteger}${trimmedDecimal ? `.${trimmedDecimal}` : ''}`;
}

function buildListParams() {
  return {
    ...query,
    lastId: isSortActive.value ? undefined : query.lastId,
    pageNo: isSortActive.value ? query.pageNo : undefined,
    sortField: isSortActive.value ? query.sortField : undefined,
    sortOrder: isSortActive.value ? query.sortOrder : undefined,
  };
}

function buildStatisticsParams() {
  return {
    sysOrigin: query.sysOrigin,
  };
}

async function loadStatistics() {
  if (!query.sysOrigin) {
    return;
  }
  statisticsLoading.value = true;
  try {
    const result = await getBankStatistics(buildStatisticsParams());
    statistics.totalEarnPoints = result?.totalEarnPoints ?? 0;
    statistics.totalConsumptionPoints = result?.totalConsumptionPoints ?? 0;
    statistics.totalBalance = result?.totalBalance ?? 0;
  } finally {
    statisticsLoading.value = false;
  }
}

watch(
  sysOriginOptions,
  (options) => {
    if (!query.sysOrigin) {
      query.sysOrigin = String(options[0]?.value || '');
    }
  },
  { immediate: true },
);

async function loadData(reset = false) {
  if (!query.sysOrigin) {
    return;
  }
  if (reset) {
    query.lastId = '';
    query.pageNo = 1;
    list.value = [];
    notData.value = false;
  }
  if (reset) {
    loading.value = true;
  } else {
    loadMoreLoading.value = true;
  }
  try {
    const result = reset
      ? await Promise.all([pageBank(buildListParams()), loadStatistics()]).then(
          ([rows]) => rows,
        )
      : await pageBank(buildListParams());
    const current = result || [];
    notData.value = current.length < Number(query.limit || 20);
    if (current.length > 0) {
      list.value = [...list.value, ...current];
      if (isSortActive.value) {
        query.pageNo += 1;
      } else {
        query.lastId = String(list.value[list.value.length - 1]?.id || '');
      }
    }
  } finally {
    loading.value = false;
    loadMoreLoading.value = false;
  }
}

function handleSearch() {
  void loadData(true);
}

function handleTableChange(_: any, __: any, sorter: any) {
  const activeSorter = Array.isArray(sorter) ? sorter[0] : sorter;
  const field = String(activeSorter?.columnKey || '');
  const order = String(activeSorter?.order || '');
  if (isBankSortOrder(order) && sortableAmountKeys.has(field)) {
    query.sortField = field;
    query.sortOrder = order;
  } else {
    query.sortField = '';
    query.sortOrder = '';
  }
  void loadData(true);
}

function openAction(record: Record<string, any>, type: 'deduct' | 'send') {
  activeRow.value = record;
  actionType.value = type;
  actionForm.userId = String(record.id || '');
  actionForm.sysOrigin = String(record.sysOrigin || '');
  actionForm.quantity = '';
  actionForm.remark = '';
  actionModalOpen.value = true;
}

function openTransfer(record: Record<string, any>) {
  activeRow.value = record;
  transferForm.userId = String(record.id || '');
  transferForm.sysOrigin = String(record.sysOrigin || '');
  transferForm.acceptUserId = '';
  transferForm.quantity = '';
  transferForm.remark = '';
  transferOpen.value = true;
}

function openRunningWater(record: Record<string, any>) {
  activeRow.value = record;
  runningWaterOpen.value = true;
}

async function submitAction() {
  if (!actionForm.userId || !String(actionForm.quantity).trim()) {
    message.warning('请填写完整信息');
    return;
  }
  loading.value = true;
  try {
    await (actionType.value === 'send' ? sendMoney : deductMoney)({ ...actionForm });
    message.success('操作成功');
    actionModalOpen.value = false;
    await loadData(true);
  } finally {
    loading.value = false;
  }
}

async function submitTransfer() {
  if (
    !transferForm.userId ||
    !transferForm.acceptUserId ||
    !String(transferForm.quantity).trim()
  ) {
    message.warning('请填写完整信息');
    return;
  }
  loading.value = true;
  try {
    await transferMoney({ ...transferForm });
    message.success('操作成功');
    transferOpen.value = false;
    await loadData(true);
  } finally {
    loading.value = false;
  }
}

async function handleExport() {
  if (exportLoading.value) {
    return;
  }
  exportLoading.value = true;
  try {
    await exprotBank({ sysOrigin: query.sysOrigin });
  } finally {
    exportLoading.value = false;
  }
}

function openImport() {
  importOpen.value = true;
}

function chooseImportFile() {
  importInput.value?.click();
}

async function handleImportChange(event: Event) {
  const target = event.target as HTMLInputElement;
  const file = target.files?.[0];
  if (!file) {
    return;
  }
  const form = new FormData();
  form.append('file', file);
  importLoading.value = true;
  try {
    await confirmImport(form);
    message.success('导入成功');
    importOpen.value = false;
    await loadData(true);
  } finally {
    importLoading.value = false;
    target.value = '';
  }
}

watch(
  () => query.sysOrigin,
  (value) => {
    if (value) {
      void loadData(true);
    }
  },
  { immediate: true },
);
</script>

<template>
  <Page title="用户银行账户">
    <Card>
      <div class="statistics-card" :class="{ 'is-loading': statisticsLoading }">
        <div class="statistics-item">
          <span class="statistics-label">所有用户获得总额</span>
          <strong>{{ formatAmount(statistics.totalEarnPoints) }}</strong>
        </div>
        <div class="statistics-item">
          <span class="statistics-label">所有用户消费总额</span>
          <strong>{{ formatAmount(statistics.totalConsumptionPoints) }}</strong>
        </div>
        <div class="statistics-item">
          <span class="statistics-label">所有用户余额</span>
          <strong>{{ formatAmount(statistics.totalBalance) }}</strong>
        </div>
      </div>

      <div class="toolbar">
        <Space wrap>
          <SysOriginSelect
            v-model:value="query.sysOrigin"
            :options="sysOriginOptions"
            style="width: 140px"
          />
          <AccountInput
            v-model:value="query.userId"
            :sys-origin="query.sysOrigin"
            placeholder="用户ID"
            style="width: 260px"
          />
          <Button :loading="loading" type="primary" @click="handleSearch">
            搜索
          </Button>
          <Button @click="createOpen = true">添加</Button>
          <Button :loading="exportLoading" @click="handleExport">导出</Button>
          <Button @click="openImport">导入</Button>
        </Space>
      </div>

      <Table
        :columns="columns"
        :data-source="list"
        :loading="loading"
        :pagination="false"
        row-key="id"
        :scroll="{ x: 1500 }"
        @change="handleTableChange"
      >
        <template #bodyCell="{ column, record, index }">
          <template v-if="column.key === 'index'">
            {{ index + 1 }}
          </template>
          <template v-else-if="column.key === 'userProfile'">
            <UserProfileLink :profile="record.userProfile" />
          </template>
          <template
            v-else-if="
              column.key === 'earnPoints' ||
              column.key === 'consumptionPoints' ||
              column.key === 'balance'
            "
          >
            {{ formatAmount(record[column.key]) }}
          </template>
          <template v-else-if="column.key === 'createTime'">
            {{ formatDate(record.createTime) }}
          </template>
          <template v-else-if="column.key === 'updateTime'">
            {{ formatDate(record.updateTime) }}
          </template>
          <template v-else-if="column.key === 'actions'">
            <Space size="small" wrap>
              <Button size="small" type="link" @click="openAction(record, 'send')">
                发送
              </Button>
              <Button size="small" type="link" @click="openAction(record, 'deduct')">
                扣除
              </Button>
              <Button size="small" type="link" @click="openTransfer(record)">
                转账
              </Button>
              <Button size="small" type="link" @click="openRunningWater(record)">
                流水
              </Button>
            </Space>
          </template>
        </template>
      </Table>

      <div v-if="list.length > 0" class="load-more">
        <span v-if="notData">已加载全部</span>
        <Button
          v-else
          :loading="loadMoreLoading"
          size="small"
          @click="loadData()"
        >
          加载更多
        </Button>
      </div>
    </Card>

    <UserBankCreateModal
      :open="createOpen"
      :sys-origin="query.sysOrigin"
      @close="createOpen = false"
      @success="
        () => {
          createOpen = false;
          void loadData(true);
        }
      "
    />

    <UserBankRunningWaterModal
      :open="runningWaterOpen"
      :row="activeRow || {}"
      @close="runningWaterOpen = false"
    />

    <Modal
      :confirm-loading="loading"
      :open="actionModalOpen"
      :title="actionType === 'send' ? '发送' : '扣除'"
      @cancel="actionModalOpen = false"
    >
      <div class="modal-grid">
        <div class="field">
          <div class="label">金额</div>
          <Input
            v-model:value="actionForm.quantity"
            :placeholder="`请输入${actionType === 'send' ? '发送' : '扣除'}金额`"
          />
        </div>
        <div class="field">
          <div class="label">对内备注</div>
          <Input
            v-model:value="actionForm.remark"
            placeholder="请输入对内备注"
          />
        </div>
      </div>

      <template #footer>
        <div class="footer">
          <Button @click="actionModalOpen = false">取消</Button>
          <Button :loading="loading" type="primary" @click="submitAction">
            提交
          </Button>
        </div>
      </template>
    </Modal>

    <Modal
      :confirm-loading="loading"
      :open="transferOpen"
      title="转账"
      @cancel="transferOpen = false"
    >
      <div class="modal-grid">
        <div class="field">
          <div class="label">收款人</div>
          <AccountInput
            v-model:value="transferForm.acceptUserId"
            :sys-origin="transferForm.sysOrigin"
            placeholder="用户账号"
          />
        </div>
        <div class="field">
          <div class="label">金额</div>
          <Input
            v-model:value="transferForm.quantity"
            placeholder="请输入转账金额"
          />
        </div>
        <div class="field">
          <div class="label">对内备注</div>
          <Input
            v-model:value="transferForm.remark"
            placeholder="请输入对内备注"
          />
        </div>
      </div>

      <template #footer>
        <div class="footer">
          <Button @click="transferOpen = false">取消</Button>
          <Button :loading="loading" type="primary" @click="submitTransfer">
            提交
          </Button>
        </div>
      </template>
    </Modal>

    <Modal
      :footer="null"
      :open="importOpen"
      title="导入数据"
      @cancel="!importLoading && (importOpen = false)"
    >
      <div class="import-box">
        <div>请选择导入文件：</div>
        <a
          href="https://dev.file.momooline.com/files/Import%20Template.xlsx"
          rel="noreferrer"
          target="_blank"
        >
          模板下载
        </a>
        <input
          ref="importInput"
          accept=".xls,.xlsx"
          class="hidden-input"
          type="file"
          @change="handleImportChange"
        />
        <Button :loading="importLoading" block @click="chooseImportFile">
          选择文件并导入
        </Button>
      </div>
    </Modal>
  </Page>
</template>

<style scoped>
.statistics-card {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  padding: 14px 16px;
  margin-bottom: 16px;
  background: #f8fafc;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
}

.statistics-card.is-loading {
  opacity: 0.68;
}

.statistics-item {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.statistics-label {
  color: #64748b;
  font-size: 13px;
}

.statistics-item strong {
  color: #0f172a;
  font-size: 20px;
  font-weight: 600;
  line-height: 1.25;
}

.toolbar {
  margin-bottom: 16px;
}

.load-more {
  padding: 20px 0 0;
  text-align: center;
}

.modal-grid {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.label {
  color: #334155;
  font-weight: 600;
}

.footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

.import-box {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.hidden-input {
  display: none;
}
</style>
