<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import api from '../api';
import { useAdminLocale } from '../composables/useAdminLocale';
import { useAuthStore } from '../stores/auth';
import { buildPlayerRegisterUrl, copyText } from '../utils/invite-link';
import AdminTableEmpty from './AdminTableEmpty.vue';
import { formatRatePercent } from '../utils/rate-percent';

export interface InviteHistoryRow {
  id: string;
  code: string;
  status: string;
  createdAt: string;
  revokedAt: string | null;
  cashbackRate: string | null;
  sponsorId: string;
  sponsorUsername: string;
  sponsorUserType: string;
  sponsorAgentLevel: number | null;
  registeredPlayerId: string | null;
  registeredPlayerUsername: string | null;
}

interface SponsorOption {
  id: string;
  username: string;
  userType: string;
  agentLevel: number | null;
}

const props = withDefaults(
  defineProps<{
    compact?: boolean;
    embedded?: boolean;
    refreshKey?: number;
  }>(),
  {
    compact: false,
    embedded: false,
    refreshKey: 0,
  },
);

const { t, locale, localeTag } = useAdminLocale();
const auth = useAuthStore();

const items = ref<InviteHistoryRow[]>([]);
const total = ref(0);
const page = ref(1);
const pageSize = ref(props.compact ? 10 : 20);
const loading = ref(false);
const filterStatus = ref('');
const filterSponsorId = ref('');
const filterKeyword = ref('');
const sponsorOptions = ref<SponsorOption[]>([]);

const showSponsorFilter = computed(() => auth.isAdmin.value || auth.isAgent.value);
const useCompactActions = computed(() => props.embedded || props.compact);

function isUsed(row: InviteHistoryRow) {
  return Boolean(row.registeredPlayerId);
}

function displayStatus(row: InviteHistoryRow) {
  if (row.status === 'ACTIVE') return 'ACTIVE';
  if (isUsed(row)) return 'USED';
  return 'REVOKED';
}

function statusLabel(row: InviteHistoryRow) {
  const status = displayStatus(row);
  if (status === 'ACTIVE') return t('invite.status.ACTIVE');
  if (status === 'USED') return t('invite.status.USED');
  if (status === 'REVOKED') return t('invite.status.REVOKED');
  return row.status;
}

function statusTagType(row: InviteHistoryRow) {
  const status = displayStatus(row);
  if (status === 'ACTIVE') return 'success';
  if (status === 'USED') return 'warning';
  return 'info';
}

function sponsorLabel(row: InviteHistoryRow) {
  if (row.sponsorUserType === 'ADMIN') return `${row.sponsorUsername} (${t('role.admin')})`;
  if (row.sponsorAgentLevel != null && row.sponsorAgentLevel > 0) {
    return `${row.sponsorUsername} (${t('role.agent_level', { n: row.sponsorAgentLevel })})`;
  }
  return row.sponsorUsername;
}

function formatTime(v: string | null) {
  if (!v) return '—';
  return new Date(v).toLocaleString(localeTag.value, {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
  });
}

async function loadSponsors() {
  if (!showSponsorFilter.value) return;
  try {
    const { data } = await api.get('/manage/invites/sponsors');
    sponsorOptions.value = (data.data.items ?? []) as SponsorOption[];
  } catch {
    sponsorOptions.value = [];
  }
}

async function load() {
  loading.value = true;
  try {
    const { data } = await api.get('/manage/invites', {
      params: {
        page: page.value,
        pageSize: pageSize.value,
        status: filterStatus.value || undefined,
        sponsorId: filterSponsorId.value || undefined,
        keyword: filterKeyword.value.trim() || undefined,
      },
    });
    items.value = (data.data.items ?? []) as InviteHistoryRow[];
    total.value = data.data.total ?? 0;
  } catch {
    items.value = [];
    total.value = 0;
    ElMessage.error(t('invite.history_load_failed'));
  } finally {
    loading.value = false;
  }
}

function onSearch() {
  page.value = 1;
  load();
}

function onPageChange(p: number) {
  page.value = p;
  load();
}

function onSizeChange(size: number) {
  pageSize.value = size;
  page.value = 1;
  load();
}

async function copyCode(code: string) {
  const ok = await copyText(code);
  ElMessage[ok ? 'success' : 'error'](ok ? t('invite.copy_code_ok') : t('invite.copy_failed'));
}

async function copyLink(code: string) {
  const ok = await copyText(buildPlayerRegisterUrl(code));
  ElMessage[ok ? 'success' : 'error'](ok ? t('invite.copy_link_ok') : t('invite.copy_failed'));
}

function canCopy(row: InviteHistoryRow) {
  return !isUsed(row);
}

function canCopyLink(row: InviteHistoryRow) {
  return row.status === 'ACTIVE' && !isUsed(row);
}

function canRevoke(row: InviteHistoryRow) {
  if (row.status !== 'ACTIVE') return false;
  if (auth.isAdmin.value) return true;
  return row.sponsorId === auth.user.value?.id;
}

function canDelete(row: InviteHistoryRow) {
  if (row.status !== 'REVOKED') return false;
  if (row.registeredPlayerId) return false;
  if (auth.isAdmin.value) return true;
  return row.sponsorId === auth.user.value?.id;
}

function registrantLabel(row: InviteHistoryRow) {
  return row.registeredPlayerUsername ?? t('invite.not_registered');
}

async function revokeRow(row: InviteHistoryRow) {
  try {
    await ElMessageBox.confirm(t('invite.revoke_confirm', { code: row.code }), t('invite.revoke_title'), {
      type: 'warning',
      confirmButtonText: t('common.confirm'),
      cancelButtonText: t('common.cancel'),
    });
  } catch {
    return;
  }

  try {
    await api.post(`/manage/invites/${row.id}/revoke`);
    ElMessage.success(t('invite.revoke_ok'));
    load();
  } catch {
    ElMessage.error(t('invite.revoke_failed'));
  }
}

async function deleteRow(row: InviteHistoryRow) {
  try {
    await ElMessageBox.confirm(t('invite.delete_confirm', { code: row.code }), t('invite.delete_title'), {
      type: 'warning',
      confirmButtonText: t('common.confirm'),
      cancelButtonText: t('common.cancel'),
    });
  } catch {
    return;
  }

  try {
    await api.delete(`/manage/invites/${row.id}`);
    ElMessage.success(t('invite.delete_ok'));
    load();
  } catch {
    ElMessage.error(t('invite.delete_failed'));
  }
}

onMounted(async () => {
  await loadSponsors();
  await load();
});

watch(
  () => props.refreshKey,
  () => {
    load();
  },
);
</script>

<template>
  <div class="invite-history" :class="{ compact, embedded }">
    <div v-if="!embedded" class="history-head">
      <span class="history-title">{{ t('invite.history_title') }}</span>
      <span v-if="!compact" class="history-hint">{{ t('invite.history_hint') }}</span>
    </div>

    <el-form inline class="history-filters" @submit.prevent="onSearch">
      <el-form-item :label="t('invite.filter_status')">
        <el-select v-model="filterStatus" clearable :placeholder="t('common.all')" style="width: 120px">
          <el-option :label="t('invite.status.ACTIVE')" value="ACTIVE" />
          <el-option :label="t('invite.status.REVOKED')" value="REVOKED" />
        </el-select>
      </el-form-item>
      <el-form-item v-if="showSponsorFilter" :label="t('invite.filter_sponsor')">
        <el-select
          v-model="filterSponsorId"
          clearable
          filterable
          :placeholder="t('common.all')"
          style="width: 180px"
        >
          <el-option
            v-for="opt in sponsorOptions"
            :key="opt.id"
            :label="opt.username"
            :value="opt.id"
          />
        </el-select>
      </el-form-item>
      <el-form-item :label="t('invite.filter_code')">
        <el-input
          v-model="filterKeyword"
          clearable
          :placeholder="t('invite.filter_code_ph')"
          style="width: 140px"
          @keyup.enter="onSearch"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="onSearch">{{ t('common.search') }}</el-button>
      </el-form-item>
    </el-form>

    <div class="table-wrap">
      <el-table
        v-loading="loading"
        :data="items"
        stripe
        size="small"
        class="history-table"
        :class="{ 'history-table--embedded': embedded }"
      >
        <template #empty>
          <AdminTableEmpty />
        </template>
        <el-table-column prop="code" :label="t('invite.code')" min-width="96" show-overflow-tooltip>
          <template #default="{ row }">
            <code class="code-cell">{{ row.code }}</code>
          </template>
        </el-table-column>
        <el-table-column :label="t('invite.col_status')" width="88" align="center">
          <template #default="{ row }">
            <el-tag :type="statusTagType(row)" size="small">{{ statusLabel(row) }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column :label="t('invite.col_sponsor')" min-width="128" show-overflow-tooltip>
          <template #default="{ row }">{{ sponsorLabel(row) }}</template>
        </el-table-column>
        <el-table-column :label="t('invite.col_registrant')" min-width="96" show-overflow-tooltip>
          <template #default="{ row }">
            <span :class="{ 'registrant-empty': !row.registeredPlayerUsername }">
              {{ registrantLabel(row) }}
            </span>
          </template>
        </el-table-column>
        <el-table-column :label="t('invite.col_cashback_rate')" width="88" align="right">
          <template #default="{ row }">
            <span v-if="row.cashbackRate != null">{{ formatRatePercent(row.cashbackRate) }}</span>
            <span v-else class="registrant-empty">—</span>
          </template>
        </el-table-column>
        <el-table-column :label="t('invite.col_created')" min-width="128" show-overflow-tooltip>
          <template #default="{ row }">{{ formatTime(row.createdAt) }}</template>
        </el-table-column>
        <el-table-column :label="t('invite.col_revoked')" min-width="128" show-overflow-tooltip>
          <template #default="{ row }">{{ formatTime(row.revokedAt) }}</template>
        </el-table-column>
        <el-table-column :label="t('common.actions')" :min-width="useCompactActions ? 220 : 260" align="center">
          <template #default="{ row }">
            <div class="action-cell" :class="{ 'action-cell--compact': useCompactActions }">
              <el-button
                link
                type="primary"
                size="small"
                :disabled="!canCopy(row)"
                @click="copyCode(row.code)"
              >
                {{ useCompactActions ? t('invite.copy_code_short') : t('invite.copy_code') }}
              </el-button>
              <el-button
                link
                type="primary"
                size="small"
                :disabled="!canCopyLink(row)"
                @click="copyLink(row.code)"
              >
                {{ useCompactActions ? t('invite.copy_link_short') : t('invite.copy_link') }}
              </el-button>
              <el-button
                link
                type="danger"
                size="small"
                :disabled="!canRevoke(row)"
                @click="revokeRow(row)"
              >
                {{ t('invite.revoke_btn') }}
              </el-button>
              <el-button
                link
                type="danger"
                size="small"
                :disabled="!canDelete(row)"
                @click="deleteRow(row)"
              >
                {{ t('common.delete') }}
              </el-button>
            </div>
          </template>
        </el-table-column>
      </el-table>
    </div>

    <div class="pager">
      <el-pagination
        v-model:current-page="page"
        v-model:page-size="pageSize"
        :total="total"
        :page-sizes="[10, 20, 50]"
        layout="total, sizes, prev, pager, next"
        background
        small
        @current-change="onPageChange"
        @size-change="onSizeChange"
      />
    </div>
  </div>
</template>

<style scoped>
.invite-history {
  border: 1px solid var(--el-border-color-light);
  border-radius: 8px;
  padding: 14px 16px;
  background: var(--el-fill-color-blank);
}

.invite-history.compact {
  padding: 10px 12px;
}

.invite-history.embedded {
  border: none;
  padding: 0;
  background: transparent;
}

.history-head {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 10px;
}

.history-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--el-text-color-primary);
}

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

.history-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  margin-bottom: 12px;
}

.history-filters :deep(.el-form-item) {
  margin-right: 0;
  margin-bottom: 0;
}

.table-wrap {
  width: 100%;
  overflow-x: auto;
}

.history-table {
  width: 100%;
}

.history-table--embedded {
  min-width: 900px;
}

.history-table :deep(.cell) {
  overflow: visible;
  text-overflow: clip;
}

.action-cell {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 2px 8px;
}

.action-cell :deep(.el-button) {
  margin: 0;
  padding: 0 2px;
  height: auto;
}

.action-cell--compact {
  gap: 2px 6px;
}

.action-cell--compact :deep(.el-button) {
  font-size: 11px;
  line-height: 1.3;
  padding: 1px 3px;
}

.action-cell :deep(.el-button.is-link) {
  border-radius: 6px;
  padding: 4px 8px;
}

.action-cell--compact :deep(.el-button.is-link) {
  padding: 3px 6px;
}

.code-cell {
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--el-color-primary);
}

.registrant-empty {
  color: var(--el-text-color-secondary);
}

.pager {
  margin-top: 12px;
  display: flex;
  justify-content: flex-end;
}
</style>
