<script setup lang="ts">
import { ElMessage } from "element-plus";
import { onMounted, reactive, ref } from "vue";

import { api } from "../services/api";
import type {
  AdminUser,
  EntitlementPlan,
  UserImportResult,
} from "../types/api";
import AdminPagination from "./AdminPagination.vue";
import TableRowActions from "./TableRowActions.vue";
import UserDetailDrawer from "./UserDetailDrawer.vue";
import UserEntitlementRenewDialog from "./UserEntitlementRenewDialog.vue";

const loading = ref(false);
const users = ref<AdminUser[]>([]);
const entitlementPlans = ref<EntitlementPlan[]>([]);
const pager = reactive({ page: 1, pageSize: 20, total: 0 });
const keyword = ref("");
const filters = reactive({
  planId: undefined as number | undefined,
  status: "all",
});
const selectedUsers = ref<AdminUser[]>([]);
const renewDialogOpen = ref(false);
const renewTargets = ref<AdminUser[]>([]);
const renewSubmitting = ref(false);
const detailOpen = ref(false);
const detailUserId = ref<number | null>(null);
const studentImportFile = ref<File | null>(null);
const studentImportInput = ref<HTMLInputElement | null>(null);
const studentImportResult = ref<UserImportResult | null>(null);
const studentForm = reactive({
  phone: "",
  name: "",
  nickname: "",
  status: 1,
  dailyChatLimit: 100,
  expiredAt: "",
});

onMounted(async () => {
  loading.value = true;
  try {
    await Promise.all([loadEntitlementPlans(), loadUsers()]);
  } finally {
    loading.value = false;
  }
});

async function loadUsers(page = 1, pageSize = pager.pageSize) {
  const result = await api.users({
    keyword: keyword.value,
    planId: filters.planId,
    entitlementStatus: filters.status,
    page,
    pageSize,
  });
  users.value = result.items;
  selectedUsers.value = [];
  Object.assign(pager, {
    page: result.page,
    pageSize: result.pageSize,
    total: result.total,
  });
}

async function reloadCurrentPage() {
  await loadUsers(pager.page, pager.pageSize);
}

async function loadEntitlementPlans() {
  entitlementPlans.value = await api.entitlementPlans(true);
}

function resetFilters() {
  keyword.value = "";
  filters.planId = undefined;
  filters.status = "all";
  void loadUsers(1);
}

function handleSelectionChange(rows: AdminUser[]) {
  selectedUsers.value = rows;
}

function openRenewDialog(targets: AdminUser[]) {
  if (!targets.length) return ElMessage.warning("请先选择需要续期的用户");
  renewTargets.value = targets;
  renewDialogOpen.value = true;
}

async function submitEntitlementRenew(payload: {
  extensionDays: number;
  remark: string;
}) {
  if (!renewTargets.value.length || renewSubmitting.value) return;
  renewSubmitting.value = true;
  const idempotencyKey =
    typeof crypto.randomUUID === "function"
      ? crypto.randomUUID()
      : `renew-${Date.now()}-${Math.random().toString(36).slice(2)}`;
  try {
    if (renewTargets.value.length === 1) {
      await api.renewUserEntitlement(renewTargets.value[0].id, {
        ...payload,
        idempotencyKey,
      });
      ElMessage.success("权益续期成功");
    } else {
      const result = await api.batchRenewUserEntitlement({
        userIds: renewTargets.value.map((user) => user.id),
        ...payload,
        idempotencyKey,
      });
      if (result.failureCount) {
        const failure = result.failed[0];
        ElMessage.warning(
          `成功 ${result.successCount} 人，失败 ${result.failureCount} 人${failure ? `；${failure.name || failure.userId}：${failure.reason}` : ""}`,
        );
      } else {
        ElMessage.success(`已为 ${result.successCount} 位用户续期`);
      }
    }
    renewDialogOpen.value = false;
    await reloadCurrentPage();
  } catch (error) {
    ElMessage.error(error instanceof Error ? error.message : "权益续期失败");
  } finally {
    renewSubmitting.value = false;
  }
}

function entitlementStatusLabel(row: AdminUser) {
  const status = row.entitlement?.lifecycleStatus;
  if (status === "expired_fallback") return "已到期，已降级";
  if (status === "expiring_7") return "7 天内到期";
  if (status === "expiring_30") return "30 天内到期";
  if (status === "long_term") return "长期有效";
  if (status === "default") return "默认权益";
  return "生效中";
}

function entitlementStatusType(row: AdminUser) {
  const status = row.entitlement?.lifecycleStatus;
  if (status === "expired_fallback") return "danger";
  if (status === "expiring_7" || status === "expiring_30") return "warning";
  if (status === "active" || status === "long_term") return "success";
  return "info";
}

function formatEntitlementDate(value?: string | null) {
  if (!value) return "长期";
  const date = new Date(value);
  return Number.isNaN(date.getTime())
    ? value
    : date.toLocaleDateString("zh-CN");
}

async function assignUserEntitlement(row: AdminUser, planId: number) {
  row.entitlement = await api.assignUserEntitlement(row.id, { planId });
  ElMessage.success("用户权益已更新");
}

function openUserDetail(row: AdminUser) {
  detailUserId.value = row.id;
  detailOpen.value = true;
}

async function saveUser(row: AdminUser) {
  await api.updateUser(row.id, {
    status: row.status,
    dailyChatLimit: row.dailyChatLimit,
  });
  ElMessage.success("用户已更新");
  await reloadCurrentPage();
}

async function createStudent() {
  if (!studentForm.phone || !studentForm.name)
    return ElMessage.error("请填写手机号和姓名");
  await api.createUser({
    phone: studentForm.phone,
    name: studentForm.name,
    nickname: studentForm.nickname || null,
    status: studentForm.status,
    dailyChatLimit: studentForm.dailyChatLimit,
    expiredAt: studentForm.expiredAt
      ? `${studentForm.expiredAt}T23:59:59`
      : null,
  });
  ElMessage.success("学员已添加");
  resetStudentForm();
  await loadUsers(1);
}

function handleStudentImportFile(event: Event) {
  studentImportFile.value =
    (event.target as HTMLInputElement).files?.[0] ?? null;
}

async function importStudents() {
  if (!studentImportFile.value) return ElMessage.error("请先选择 Excel 文件");
  studentImportResult.value = await api.importUsersExcel(
    studentImportFile.value,
  );
  ElMessage.success(
    `导入完成：新增 ${studentImportResult.value.created}，更新 ${studentImportResult.value.updated}，失败 ${studentImportResult.value.failed}`,
  );
  studentImportFile.value = null;
  if (studentImportInput.value) studentImportInput.value.value = "";
  await loadUsers(1);
}

function resetStudentForm() {
  Object.assign(studentForm, {
    phone: "",
    name: "",
    nickname: "",
    status: 1,
    dailyChatLimit: 100,
    expiredAt: "",
  });
}

async function deleteUser(row: AdminUser) {
  if (
    !window.confirm(
      `确认删除用户 ${row.phone} 吗？删除后前台将无法继续使用该账号。`,
    )
  )
    return;
  await api.deleteUser(row.id);
  ElMessage.success("用户已删除");
  await reloadCurrentPage();
}
</script>

<template>
  <section v-loading="loading" class="feature-page">
    <div class="page-head inline">
      <div>
        <h2>用户管理</h2>
        <p>维护学员名单；只有名单内启用学员可以登录用户端。</p>
      </div>
    </div>
    <section class="student-tools">
      <div class="student-tool-panel">
        <h3>手动添加学员</h3>
        <div class="student-form-grid">
          <el-input v-model="studentForm.phone" placeholder="手机号" />
          <el-input v-model="studentForm.name" placeholder="姓名" />
          <el-input v-model="studentForm.nickname" placeholder="昵称（可选）" />
          <el-input-number v-model="studentForm.dailyChatLimit" :min="0" />
          <label class="record-date-field student-expiry-field">
            <span>有效期</span>
            <input
              v-model="studentForm.expiredAt"
              type="date"
              aria-label="学员有效期"
              title="留空表示长期有效"
            />
          </label>
          <div class="student-status-field">
            <span>启用</span>
            <el-switch
              v-model="studentForm.status"
              :active-value="1"
              :inactive-value="0"
              aria-label="启用学员账号"
            />
          </div>
        </div>
        <div class="actions compact">
          <el-button type="primary" @click="createStudent">添加学员</el-button>
          <el-button @click="resetStudentForm">清空</el-button>
        </div>
      </div>
      <div class="student-tool-panel">
        <h3>批量导入学员</h3>
        <p class="tool-help">下载模板后填写学员信息，再上传 .xlsx 文件导入。</p>
        <div class="student-file-import">
          <input
            ref="studentImportInput"
            class="file-input"
            type="file"
            accept=".xlsx"
            @change="handleStudentImportFile"
          />
          <span class="file-name">{{
            studentImportFile?.name || "未选择文件"
          }}</span>
        </div>
        <div class="actions compact">
          <el-button @click="api.downloadStudentTemplate()">下载模板</el-button>
          <el-button type="primary" @click="importStudents"
            >导入 Excel</el-button
          >
          <span v-if="studentImportResult" class="import-result"
            >新增 {{ studentImportResult.created }}，更新
            {{ studentImportResult.updated }}，失败
            {{ studentImportResult.failed }}</span
          >
        </div>
        <div
          v-if="studentImportResult?.failures.length"
          class="import-failures"
        >
          <span
            v-for="failure in studentImportResult.failures.slice(0, 5)"
            :key="`${failure.row}-${failure.phone}`"
            >第 {{ failure.row }} 行 {{ failure.phone || "-" }}：{{
              failure.reason
            }}</span
          >
        </div>
      </div>
    </section>
    <section class="user-list-toolbar">
      <el-input
        v-model="keyword"
        placeholder="手机号或姓名"
        clearable
        @keyup.enter="loadUsers(1)"
      />
      <el-select v-model="filters.planId" placeholder="全部权益版本" clearable>
        <el-option
          v-for="plan in entitlementPlans.filter((item) => item.status === 1)"
          :key="plan.id"
          :label="plan.name"
          :value="plan.id"
        />
      </el-select>
      <el-select v-model="filters.status" aria-label="权益状态">
        <el-option label="全部权益状态" value="all" /><el-option
          label="生效中"
          value="active"
        />
        <el-option label="7 天内到期" value="expiring7" /><el-option
          label="8-30 天内到期"
          value="expiring30"
        />
        <el-option label="已到期" value="expired" /><el-option
          label="使用默认权益"
          value="default"
        />
      </el-select>
      <el-button type="primary" @click="loadUsers(1)">筛选</el-button>
      <el-button @click="resetFilters">重置</el-button>
      <el-button
        class="batch-renew-button"
        :disabled="!selectedUsers.length"
        @click="openRenewDialog(selectedUsers)"
        >批量续期{{
          selectedUsers.length ? `（${selectedUsers.length}）` : ""
        }}</el-button
      >
    </section>
    <el-table :data="users" stripe @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="48" /><el-table-column
        prop="id"
        label="ID"
        width="80"
      />
      <el-table-column
        prop="phone"
        label="手机号"
        width="150"
      /><el-table-column prop="name" label="姓名" width="140" />
      <el-table-column prop="nickname" label="昵称" width="140" />
      <el-table-column label="注册来源" width="130">
        <template #default="{ row }">
          <el-tag v-if="row.registrationSource === 'sso'" type="info">第三方接入</el-tag>
          <el-tag v-else>直接学员</el-tag>
        </template>
      </el-table-column>
      <el-table-column label="状态" width="130"
        ><template #default="{ row }"
          ><el-switch
            v-model="row.status"
            :active-value="1"
            :inactive-value="0" /></template
      ></el-table-column>
      <el-table-column label="每日额度" width="150"
        ><template #default="{ row }"
          ><el-input-number
            v-model="row.dailyChatLimit"
            :min="0"
            size="small" /></template
      ></el-table-column>
      <el-table-column prop="dailyChatUsed" label="已用" width="90" />
      <el-table-column label="权益版本" min-width="300">
        <template #default="{ row }">
          <div class="user-entitlement-cell">
            <el-select
              :model-value="row.entitlement?.planId"
              placeholder="默认基础版"
              size="small"
              @change="(planId: number) => assignUserEntitlement(row, planId)"
            >
              <el-option
                v-for="plan in entitlementPlans.filter(
                  (item) => item.status === 1,
                )"
                :key="plan.id"
                :label="plan.name"
                :value="plan.id"
              />
            </el-select>
            <small
              >{{ row.entitlement?.name || "默认基础版" }} ·
              {{
                row.entitlement?.lifecycleStatus === "expired_fallback"
                  ? `原 ${row.entitlement?.previousPlanName || "权益"} ${formatEntitlementDate(row.entitlement?.previousExpiredAt)} 到期`
                  : `有效至 ${formatEntitlementDate(row.entitlement?.expiredAt)}`
              }}</small
            >
            <div class="entitlement-meta-row">
              <el-tag size="small" :type="entitlementStatusType(row)">{{
                entitlementStatusLabel(row)
              }}</el-tag
              ><span
                >本月主题 {{ row.entitlement?.monthlyTopicUsed ?? 0 }}/{{
                  row.entitlement?.monthlyTopicLimit ?? "不限"
                }}</span
              >
            </div>
          </div>
        </template>
      </el-table-column>
      <el-table-column prop="lastLoginAt" label="最近登录" width="180" />
      <el-table-column label="操作" width="210" fixed="right">
        <template #default="{ row }">
          <TableRowActions>
            <el-button size="small" @click="openUserDetail(row)"
              >详情</el-button
            >
            <el-button size="small" type="primary" @click="saveUser(row)"
              >保存</el-button
            >
            <el-dropdown trigger="click"
              ><el-button size="small">更多</el-button
              ><template #dropdown
                ><el-dropdown-menu
                  ><el-dropdown-item @click="openRenewDialog([row])"
                    >权益续期</el-dropdown-item
                  ><el-dropdown-item @click="deleteUser(row)"
                    >删除用户</el-dropdown-item
                  ></el-dropdown-menu
                ></template
              ></el-dropdown
            >
          </TableRowActions>
        </template>
      </el-table-column>
    </el-table>
    <AdminPagination
      :page="pager.page"
      :page-size="pager.pageSize"
      :total="pager.total"
      @change="loadUsers"
    />
    <UserEntitlementRenewDialog
      v-model="renewDialogOpen"
      :users="renewTargets"
      :submitting="renewSubmitting"
      @submit="submitEntitlementRenew"
    />
    <UserDetailDrawer v-model="detailOpen" :user-id="detailUserId" />
  </section>
</template>
