<script setup lang="ts">
import { ref, watch, h } from 'vue';
import { useRouter } from 'vue-router';
import { ElMessage, ElMessageBox, ElDatePicker } from 'element-plus';
import { useAdminLocale } from '../../composables/useAdminLocale';
import api from '../../api';
import MatchArchiveDialog from '../../components/MatchArchiveDialog.vue';
import { ensureLeagueExpanded } from '../../utils/matchesListState';
import { formatAmount } from '../../utils/format-amount';
const props = defineProps<{
  leagueId: string;
  filterStatus: string;
  keyword: string;
}>();

const emit = defineEmits<{
  changed: [];
  'add-match': [];
}>();

const { t, locale } = useAdminLocale();
const router = useRouter();
const archiveVisible = ref(false);
const archiveMatchId = ref('');
const archiveTitle = ref('');
const matches = ref<unknown[]>([]);
const loading = ref(false);
const matchPage = ref(1);
const matchPageSize = ref(20);
const matchTotal = ref(0);
let loadTimer: ReturnType<typeof setTimeout> | null = null;

async function load() {
  loading.value = true;
  try {
    const { data } = await api.get(`/admin/leagues/${props.leagueId}/matches`, {
      params: {
        status: props.filterStatus || undefined,
        keyword: props.keyword.trim() || undefined,
        locale: locale.value,
        page: matchPage.value,
        pageSize: matchPageSize.value,
      },
    });
    const payload = data.data as {
      items: unknown[];
      total: number;
      page: number;
      pageSize: number;
    };
    matches.value = payload.items;
    matchTotal.value = payload.total;
    matchPage.value = payload.page;
    matchPageSize.value = payload.pageSize;
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.load_matches_failed'));
  } finally {
    loading.value = false;
  }
}

function scheduleLoad(resetPage = false) {
  if (resetPage) matchPage.value = 1;
  if (loadTimer) clearTimeout(loadTimer);
  loadTimer = setTimeout(() => {
    loadTimer = null;
    void load();
  }, 200);
}

watch(
  () => [props.leagueId, props.filterStatus, props.keyword] as const,
  () => scheduleLoad(true),
  { immediate: true },
);

function onMatchPageChange(page: number) {
  matchPage.value = page;
  void load();
}

function onMatchPageSizeChange(size: number) {
  matchPageSize.value = size;
  matchPage.value = 1;
  void load();
}

function notifyParent() {
  emit('changed');
  load();
}

async function publish(id: string) {
  await api.post(`/admin/matches/${id}/publish`);
  await api.post(`/admin/matches/${id}/markets/templates`, {
    marketTypes: [
      'FT_1X2',
      'FT_HANDICAP',
      'FT_OVER_UNDER',
      'FT_ODD_EVEN',
      'HT_1X2',
      'HT_HANDICAP',
      'HT_OVER_UNDER',
      'FT_CORRECT_SCORE',
      'HT_CORRECT_SCORE',
      'SH_CORRECT_SCORE',
    ],
  });
  ElMessage.success(t('msg.published'));
  notifyParent();
}

async function unpublish(id: string) {
  try {
    await ElMessageBox.confirm(t('match.confirm_unpublish'), t('common.confirm'), {
      type: 'warning',
      confirmButtonText: t('match.btn.unpublish'),
      cancelButtonText: t('common.cancel'),
    });
  } catch {
    return;
  }
  await api.post(`/admin/matches/${id}/unpublish`);
  ElMessage.success(t('msg.match_unpublished'));
  notifyParent();
}

async function close(id: string) {
  await api.post(`/admin/matches/${id}/close`);
  ElMessage.success(t('msg.closed'));
  notifyParent();
}

function beforeLeaveList() {
  ensureLeagueExpanded(props.leagueId);
}

function openManage(id: string) {
  beforeLeaveList();
  router.push(`/matches/${id}/edit`);
}

function openMarkets(id: string) {
  beforeLeaveList();
  router.push(`/matches/${id}/markets`);
}

function settle(id: string) {
  beforeLeaveList();
  router.push(`/settlement/${id}`);
}

type TagType = '' | 'info' | 'success' | 'warning' | 'danger';
function matchStatusText(status: string) {
  const key = `match.status.${status}`;
  const v = t(key);
  return v !== key ? v : status;
}
const statusTagTypes: Record<string, TagType> = {
  DRAFT: 'info',
  PUBLISHED: 'warning',
  CLOSED: 'danger',
  SETTLED: 'success',
};

function rowOf(row: unknown) {
  return row as Record<string, unknown>;
}
function matchStatus(row: unknown) {
  return String(rowOf(row).status ?? '');
}
function matchStatusLabel(row: unknown) {
  return matchStatusText(matchStatus(row));
}
function matchStatusType(row: unknown): TagType {
  return statusTagTypes[matchStatus(row)] ?? 'info';
}
function matchId(row: unknown) {
  return String(rowOf(row).id ?? '');
}
function matchTime(row: unknown) {
  return new Date(String(rowOf(row).startTime)).toLocaleString();
}
function betCount(row: unknown) {
  return Number(rowOf(row).betCount ?? 0);
}
function totalStake(row: unknown) {
  return formatAmount(String(rowOf(row).totalStake ?? '0'));
}
function pendingBets(row: unknown) {
  return Number(rowOf(row).pendingBets ?? 0);
}

function matchTitle(row: unknown) {
  const r = rowOf(row);
  const home =
    String(r.homeTeamName ?? '').trim() ||
    (r.homeTeam as { code?: string })?.code ||
    '';
  const away =
    String(r.awayTeamName ?? '').trim() ||
    (r.awayTeam as { code?: string })?.code ||
    '';
  if (home && away) return `${home} vs ${away}`;
  const matchName = String(r.matchName ?? '').trim();
  return matchName || '—';
}
function canManage(row: unknown) {
  const s = matchStatus(row);
  return s === 'DRAFT' || s === 'PUBLISHED';
}
function canDeleteRow(_row: unknown) {
  return true;
}
function openArchive(row: unknown) {
  archiveMatchId.value = matchId(row);
  archiveTitle.value = matchTitle(row);
  archiveVisible.value = true;
}
function onMatchArchived() {
  notifyParent();
}
function canPublishRow(row: unknown) {
  return matchStatus(row) === 'DRAFT';
}
function canUnpublishRow(row: unknown) {
  const s = matchStatus(row);
  return s === 'PUBLISHED' || s === 'CLOSED' || s === 'PENDING_SETTLEMENT';
}
function canCloseRow(row: unknown) {
  return matchStatus(row) === 'PUBLISHED';
}
function canReopenRow(row: unknown) {
  const s = matchStatus(row);
  return s === 'CLOSED' || s === 'PENDING_SETTLEMENT';
}
function canSettleRow(row: unknown) {
  const s = matchStatus(row);
  return s === 'CLOSED' || s === 'PENDING_SETTLEMENT' || s === 'SETTLED';
}
function settleButtonLabel(row: unknown) {
  return matchStatus(row) === 'SETTLED' ? t('common.resettle') : t('common.settle');
}
function kickoffPassed(row: unknown) {
  return new Date(String(rowOf(row).startTime)) <= new Date();
}

async function promptReopenKickoff(): Promise<string | null> {
  const kickoff = ref('');
  try {
    await ElMessageBox({
      title: t('match.reopen_kickoff_title'),
      message: () =>
        h('div', { class: 'reopen-kickoff-prompt' }, [
          h(
            'p',
            {
              style: 'margin: 0 0 12px; font-size: 13px; color: var(--el-text-color-secondary)',
            },
            t('match.reopen_kickoff_hint'),
          ),
          h(ElDatePicker, {
            modelValue: kickoff.value,
            'onUpdate:modelValue': (v: string) => {
              kickoff.value = v;
            },
            type: 'datetime',
            valueFormat: 'YYYY-MM-DDTHH:mm:ss',
            style: 'width: 100%',
          }),
        ]),
      showCancelButton: true,
      confirmButtonText: t('common.confirm'),
      cancelButtonText: t('common.cancel'),
      beforeClose: (action, _instance, done) => {
        if (action === 'confirm') {
          if (!kickoff.value || new Date(kickoff.value) <= new Date()) {
            ElMessage.warning(t('match.reopen_kickoff_invalid'));
            return;
          }
        }
        done();
      },
    });
    return kickoff.value || null;
  } catch {
    return null;
  }
}

async function reopenRow(row: unknown) {
  const id = matchId(row);
  let startTime: string | undefined;
  if (kickoffPassed(row)) {
    const picked = await promptReopenKickoff();
    if (!picked) return;
    startTime = picked;
  }
  try {
    await api.post(`/admin/matches/${id}/reopen`, startTime ? { startTime } : {});
    ElMessage.success(t('msg.reopened'));
    notifyParent();
  } catch (e) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.save_failed'));
  }
}

async function confirmDelete(row: unknown) {
  openArchive(row);
}

defineExpose({ reload: load });
</script>

<template>
  <div class="league-matches-panel">
    <el-table v-loading="loading" :data="matches" stripe row-key="id" class="nested-match-table">
      <el-table-column prop="id" label="ID" width="64" />
      <el-table-column :label="t('match.col.matchup')" min-width="180">
        <template #default="{ row }">
          <span class="matchup-link">{{ matchTitle(row) }}</span>
        </template>
      </el-table-column>
      <el-table-column :label="t('common.status')" width="88">
        <template #default="{ row }">
          <el-tag :type="matchStatusType(row)" size="small">{{ matchStatusLabel(row) }}</el-tag>
        </template>
      </el-table-column>
      <el-table-column :label="t('match.col.kickoff')" min-width="150">
        <template #default="{ row }">{{ matchTime(row) }}</template>
      </el-table-column>
      <el-table-column :label="t('match.col.bet_count')" width="72" align="center">
        <template #default="{ row }">
          <span :class="{ 'bet-stat-active': betCount(row) > 0 }">{{ betCount(row) }}</span>
        </template>
      </el-table-column>
      <el-table-column :label="t('match.col.total_stake')" width="100" align="right">
        <template #default="{ row }">{{ totalStake(row) }}</template>
      </el-table-column>
      <el-table-column :label="t('match.col.pending_bets')" width="80" align="center">
        <template #default="{ row }">
          <el-tag v-if="pendingBets(row) > 0" type="warning" size="small" effect="plain">
            {{ pendingBets(row) }}
          </el-tag>
          <span v-else class="bet-stat-zero">0</span>
        </template>
      </el-table-column>
      <el-table-column width="460" align="center">
        <template #header>
          <div class="actions-col-header">
            <span class="actions-col-header__label">{{ t('common.actions') }}</span>
            <el-button type="primary" size="small" @click.stop="emit('add-match')">
              {{ t('match.create_fixture_btn') }}
            </el-button>
          </div>
        </template>
        <template #default="{ row }">
          <div class="action-btns">
            <div class="action-group">
              <el-button
                size="small"
                type="primary"
                :disabled="!canManage(row)"
                @click="openManage(matchId(row))"
              >
                {{ t('matchEditor.manage_btn') }}
              </el-button>
              <el-button
                size="small"
                type="primary"
                plain
                :disabled="!canManage(row)"
                @click="openMarkets(matchId(row))"
              >
                {{ t('match.btn.markets') }}
              </el-button>
            </div>
            <div class="action-group">
              <el-button
                v-if="canPublishRow(row)"
                size="small"
                type="success"
                @click="publish(matchId(row))"
              >
                {{ t('common.publish') }}
              </el-button>
              <el-button
                v-else-if="canUnpublishRow(row)"
                size="small"
                type="warning"
                @click="unpublish(matchId(row))"
              >
                {{ t('match.btn.unpublish') }}
              </el-button>
              <el-button
                size="small"
                type="warning"
                :disabled="!canCloseRow(row)"
                @click="close(matchId(row))"
              >
                {{ t('common.close_betting') }}
              </el-button>
              <el-button
                size="small"
                type="success"
                plain
                :disabled="!canReopenRow(row)"
                @click="reopenRow(row)"
              >
                {{ t('common.reopen_betting') }}
              </el-button>
              <el-button
                size="small"
                type="primary"
                :disabled="!canSettleRow(row)"
                @click="settle(matchId(row))"
              >
                {{ settleButtonLabel(row) }}
              </el-button>
            </div>
            <el-button
              size="small"
              type="danger"
              plain
              @click="confirmDelete(row)"
            >
              {{ t('common.delete') }}
            </el-button>
          </div>
        </template>
      </el-table-column>
    </el-table>
    <p v-if="!loading && !matches.length" class="empty-hint">{{ t('match.no_fixtures') }}</p>
    <div v-if="matchTotal > matchPageSize" class="nested-pager">
      <el-pagination
        v-model:current-page="matchPage"
        v-model:page-size="matchPageSize"
        :total="matchTotal"
        :page-sizes="[10, 20, 50]"
        layout="total, sizes, prev, pager, next"
        small
        @current-change="onMatchPageChange"
        @size-change="onMatchPageSizeChange"
      />
    </div>
    <MatchArchiveDialog
      v-model="archiveVisible"
      :match-id="archiveMatchId"
      :title="archiveTitle"
      @archived="onMatchArchived"
    />
  </div>
</template>

<style scoped>
.league-matches-panel {
  padding: 10px 12px 12px;
  background: #0a0a0a;
}
.nested-pager {
  display: flex;
  justify-content: flex-end;
  padding-top: 8px;
}
.actions-col-header {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 0 4px;
  box-sizing: border-box;
  white-space: nowrap;
}

.actions-col-header__label {
  font-size: 12px;
  font-weight: 600;
  color: #aaa;
  line-height: 1;
}

.actions-col-header :deep(.el-button) {
  margin: 0 !important;
  padding: 6px 10px !important;
  height: 28px !important;
  min-height: 28px !important;
  font-size: 12px !important;
  font-weight: 600;
  border-radius: 6px;
  white-space: nowrap;
}

.nested-match-table :deep(.el-table__header .el-table__cell) {
  padding: 6px 0;
}

.nested-match-table :deep(.el-table__header .cell) {
  overflow: visible;
}
.empty-hint {
  font-size: 12px;
  color: #666;
  margin: 8px 0 0;
}
.matchup-link {
  color: var(--green-text);
}
.bet-stat-active {
  color: var(--green-text);
  font-weight: 600;
}
.bet-stat-zero {
  color: #555;
}
.action-btns {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 8px;
  justify-content: center;
}
.action-group {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 2px 4px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid rgba(255, 255, 255, 0.05);
}
.action-btns :deep(.el-button) {
  margin: 0 !important;
  min-width: 52px;
  padding: 4px 10px !important;
  font-size: 12px !important;
  border-radius: 6px;
}

.action-btns :deep(.el-button:not(.is-disabled):not(:disabled)) {
  cursor: pointer;
}

.action-btns :deep(.el-button.is-disabled),
.action-btns :deep(.el-button:disabled) {
  cursor: not-allowed;
}
</style>
