<script setup lang="ts">
import { ref, watch, h, defineAsyncComponent } 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 { formatAmount } from '../../utils/format-amount';
import {
  formatPlatformMatchDateTime,
  platformPickerDateTimeToIso,
} from '@thebet365/shared';

const MatchEventEditor = defineAsyncComponent(
  () => import('./MatchEventEditor.vue'),
);
const MatchMarketsPanel = defineAsyncComponent(
  () => import('./MatchMarketsPanel.vue'),
);
const props = withDefaults(
  defineProps<{
    leagueId: string;
    filterStatus?: string;
    keyword?: string;
  }>(),
  {
    filterStatus: '',
    keyword: '',
  },
);

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

const { t, locale } = useAdminLocale();
const router = useRouter();
const archiveVisible = ref(false);
const archiveMatchId = ref('');
const archiveTitle = ref('');
const manageDialogVisible = ref(false);
const marketsDialogVisible = ref(false);
const dialogMatchId = ref('');
const dialogMatchTitle = ref('');
const filterHasBets = ref(false);
const orderBy = ref('default');
const localKeyword = ref('');
const localStatus = ref('');
const kickoffRange = ref<[string, string] | null>(null);

const matches = ref<unknown[]>([]);
const loading = ref(false);
const matchPage = ref(1);
const matchPageSize = ref(10);
const matchTotal = ref(0);
let loadTimer: ReturnType<typeof setTimeout> | null = null;

watch(
  () => props.keyword,
  (value) => {
    localKeyword.value = value ?? '';
    scheduleLoad(true);
  },
  { immediate: true },
);

watch(
  () => props.filterStatus,
  (value) => {
    localStatus.value = value ?? '';
    scheduleLoad(true);
  },
  { immediate: true },
);

watch(
  () => props.leagueId,
  () => scheduleLoad(true),
  { immediate: true },
);

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

function onFilterChange() {
  matchPage.value = 1;
  void load();
}

function resetFilters() {
  localKeyword.value = '';
  localStatus.value = '';
  kickoffRange.value = null;
  filterHasBets.value = false;
  orderBy.value = 'default';
  onFilterChange();
}

async function load() {
  loading.value = true;
  try {
    const { data } = await api.get(`/admin/leagues/${props.leagueId}/matches`, {
      params: {
        status: localStatus.value || undefined,
        keyword: localKeyword.value.trim() || undefined,
        locale: locale.value,
        page: matchPage.value,
        pageSize: matchPageSize.value,
        hasBets: filterHasBets.value ? 'true' : undefined,
        orderBy: orderBy.value !== 'default' ? orderBy.value : undefined,
        startFrom: kickoffRange.value?.[0]
          ? platformPickerDateTimeToIso(kickoffRange.value[0])
          : undefined,
        startTo: kickoffRange.value?.[1]
          ? platformPickerDateTimeToIso(kickoffRange.value[1])
          : undefined,
      },
    });
    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 (!props.leagueId) return;
  if (resetPage) matchPage.value = 1;
  if (loadTimer) clearTimeout(loadTimer);
  loadTimer = setTimeout(() => {
    loadTimer = null;
    void load();
  }, 200);
}

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 openManage(id: string, title?: string) {
  dialogMatchId.value = id;
  dialogMatchTitle.value = title?.trim() || `#${id}`;
  manageDialogVisible.value = true;
}

function openMarkets(id: string, title?: string) {
  dialogMatchId.value = id;
  dialogMatchTitle.value = title?.trim() || `#${id}`;
  marketsDialogVisible.value = true;
}

function onManageSaved() {
  manageDialogVisible.value = false;
  notifyParent();
}

function settle(id: string) {
  void router.push({
    path: `/settlement/${id}`,
    query: { returnTo: `/matches/leagues/${props.leagueId}` },
  });
}

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 formatPlatformMatchDateTime(String(rowOf(row).startTime), locale.value);
}
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(
            'p',
            {
              style: 'margin: 0 0 12px; font-size: 12px; color: var(--el-text-color-secondary)',
            },
            t('match.timezone.platform_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') {
          const iso = kickoff.value ? platformPickerDateTimeToIso(kickoff.value) : '';
          if (!iso || Number.isNaN(new Date(iso).getTime()) || new Date(iso) <= new Date()) {
            ElMessage.warning(t('match.reopen_kickoff_invalid'));
            return;
          }
        }
        done();
      },
    });
    return kickoff.value ? platformPickerDateTimeToIso(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">
    <div class="nested-panel-toolbar">
      <div class="nested-panel-toolbar__filters">
        <div class="nested-panel-toolbar__field">
          <span class="nested-panel-toolbar__label">{{ t('common.keyword') }}</span>
          <el-input
            v-model="localKeyword"
            :placeholder="t('match.filter.keyword_ph')"
            clearable
            size="small"
            style="width: 168px"
            @keyup.enter="onSearch"
          />
        </div>
        <div class="nested-panel-toolbar__field">
          <span class="nested-panel-toolbar__label">{{ t('common.status') }}</span>
          <el-select
            v-model="localStatus"
            :placeholder="t('common.all')"
            clearable
            size="small"
            style="width: 120px"
            @change="onFilterChange"
          >
            <el-option :label="t('match.status.DRAFT')" value="DRAFT" />
            <el-option :label="t('match.status.PUBLISHED')" value="PUBLISHED" />
            <el-option :label="t('match.status.CLOSED')" value="CLOSED" />
            <el-option :label="t('match.status.PENDING_SETTLEMENT')" value="PENDING_SETTLEMENT" />
            <el-option :label="t('match.status.SETTLED')" value="SETTLED" />
          </el-select>
        </div>
        <div class="nested-panel-toolbar__field nested-panel-toolbar__field--range">
          <span class="nested-panel-toolbar__label">{{ t('match.field.kickoff') }}</span>
          <el-date-picker
            v-model="kickoffRange"
            type="datetimerange"
            value-format="YYYY-MM-DDTHH:mm:ss"
            :start-placeholder="t('match.filter.kickoff_from')"
            :end-placeholder="t('match.filter.kickoff_to')"
            size="small"
            clearable
            style="width: 320px"
            @change="onFilterChange"
          />
        </div>
        <el-button type="primary" size="small" @click="onSearch">
          {{ t('common.search') }}
        </el-button>
        <el-button size="small" @click="resetFilters">
          {{ t('common.reset') }}
        </el-button>
      </div>
      <div class="nested-panel-toolbar__extras">
        <el-checkbox v-model="filterHasBets" size="default" @change="onFilterChange">
          {{ t('match.filter.has_bets') }}
        </el-checkbox>
        <el-select v-model="orderBy" size="small" style="width: 148px;" @change="onFilterChange">
          <el-option :label="t('match.sort.default')" value="default" />
          <el-option :label="t('match.sort.kickoff_asc')" value="kickoffAsc" />
          <el-option :label="t('match.sort.kickoff_desc')" value="kickoffDesc" />
          <el-option :label="t('match.sort.bet_count')" value="betCount" />
          <el-option :label="t('match.sort.total_stake')" value="totalStake" />
        </el-select>
      </div>
    </div>

    <div class="nested-table-wrap">
      <el-table v-loading="loading" :data="matches" stripe row-key="id" class="nested-match-table">
      <el-table-column type="index" :index="(i: number) => (matchPage - 1) * matchPageSize + i + 1" :label="t('common.seq')" width="70" align="center" />
      <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="190">
        <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 min-width="360" align="center">
        <template #header>
          <div class="actions-col-header">
            <span class="actions-col-header__label">{{ t('common.actions') }}</span>
          </div>
        </template>
        <template #default="{ row }">
          <div class="action-btns">
            <div class="action-row action-row--primary">
              <el-button
                size="small"
                type="primary"
                :disabled="!canManage(row)"
                @click.stop="openManage(matchId(row), matchTitle(row))"
              >
                {{ t('matchEditor.manage_btn') }}
              </el-button>
              <el-button
                size="small"
                type="primary"
                plain
                class="action-btn--markets"
                :disabled="!canManage(row)"
                @click.stop="openMarkets(matchId(row), matchTitle(row))"
              >
                {{ t('match.btn.markets') }}
              </el-button>
              <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>
            </div>
            <div class="action-row action-row--workflow">
              <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>
              <el-button
                size="small"
                type="danger"
                plain
                @click="confirmDelete(row)"
              >
                {{ t('common.delete') }}
              </el-button>
            </div>
          </div>
        </template>
      </el-table-column>
      </el-table>
      <p v-if="!loading && !matches.length" class="empty-hint">{{ t('match.no_fixtures') }}</p>
    </div>

    <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"
    />
    <el-dialog
      v-model="manageDialogVisible"
      :title="`${t('matchEditor.title')} · ${dialogMatchTitle}`"
      width="920px"
      top="4vh"
      destroy-on-close
      append-to-body
      class="match-manage-dialog"
    >
      <MatchEventEditor
        v-if="manageDialogVisible && dialogMatchId"
        :match-id-prop="dialogMatchId"
        embedded
        @saved="onManageSaved"
      />
    </el-dialog>
    <el-dialog
      v-model="marketsDialogVisible"
      :title="`${t('matchEditor.section_markets')} · ${dialogMatchTitle}`"
      width="min(1200px, 96vw)"
      top="3vh"
      destroy-on-close
      append-to-body
      class="match-markets-dialog"
    >
      <div v-if="marketsDialogVisible && dialogMatchId" class="match-markets-dialog__body">
        <MatchMarketsPanel :match-id="dialogMatchId" />
      </div>
    </el-dialog>
  </div>
</template>

<style scoped>
.league-matches-panel {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  height: 100%;
  width: min(100%, calc(100vw - 272px));
  max-width: calc(100vw - 272px);
  padding: 14px 14px 14px;
  overflow: hidden;
  background: #fbfaf7;
}
.nested-panel-toolbar {
  flex-shrink: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px 16px;
  margin: 2px 0 12px;
  padding: 10px 14px;
  background: #ffffff;
  border: 1px solid var(--border-soft, #eaeaea);
  border-radius: 6px;
}

.nested-panel-toolbar__filters,
.nested-panel-toolbar__extras {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
}

.nested-panel-toolbar__field {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.nested-panel-toolbar__field--range {
  min-width: 0;
}

.nested-panel-toolbar__label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
}
.nested-table-wrap {
  flex: 1;
  min-height: 0;
  overflow: auto;
  border: 1px solid var(--border-soft, #eaeaea);
  border-radius: 6px;
  background: #ffffff;
}
.nested-table-wrap :deep(.el-table__header-wrapper) {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--el-table-header-bg-color, #fafafa);
}
.nested-pager {
  flex-shrink: 0;
  display: flex;
  justify-content: flex-end;
  padding-top: 8px;
  background: #fbfaf7;
}
.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: 700;
  color: var(--text-muted);
  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),
.nested-match-table :deep(.el-table__body .cell) {
  overflow: visible;
}

.nested-match-table :deep(.el-table__body td.el-table__cell) {
  padding-top: 8px;
  padding-bottom: 8px;
}
.empty-hint {
  font-size: 12px;
  color: var(--text-muted);
  margin: 8px 0 0;
}
.matchup-link {
  color: var(--primary-link);
}
.bet-stat-active {
  color: var(--success-text);
  font-weight: 600;
}
.bet-stat-zero {
  color: #aaa49a;
}
.action-btns {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 0;
  width: 100%;
}
.action-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 4px 5px;
  min-width: 0;
  width: 100%;
  padding: 4px 6px;
  box-sizing: border-box;
  border-radius: 8px;
  background: #ffffff;
  border: 1px solid var(--border-soft);
}
.action-row--primary {
  background: #fbfaf7;
}
.action-row--workflow {
  background: #ffffff;
}
.action-btns :deep(.el-button) {
  margin: 0 !important;
  min-width: 48px;
  min-height: 24px !important;
  height: auto !important;
  padding: 4px 9px !important;
  font-size: 12px !important;
  line-height: 1.2 !important;
  border-radius: 6px;
  white-space: nowrap;
}

.action-btns :deep(.action-btn--markets:not(.is-disabled):not(:disabled)) {
  background: var(--info-bg) !important;
  border-color: var(--info-border) !important;
  color: var(--info-text) !important;
}

.action-btns :deep(.action-btn--markets:not(.is-disabled):not(:disabled):hover),
.action-btns :deep(.action-btn--markets:not(.is-disabled):not(:disabled):focus) {
  background: #d5ecfb !important;
  border-color: #9fd0ed !important;
  color: #155b86 !important;
}

.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;
}

@media (max-width: 760px) {
  .league-matches-panel {
    width: calc(100vw - 32px);
    max-width: calc(100vw - 32px);
    overflow-x: auto;
  }

  .nested-panel-toolbar,
  .nested-pager {
    justify-content: flex-start;
  }

  .action-btns {
    justify-content: flex-start;
  }
}

.match-markets-dialog__body {
  height: min(78vh, 900px);
  overflow: hidden;
}
</style>
