<script setup lang="ts">
import { ref, computed, watch } from 'vue';
import { useRoute } from 'vue-router';
import { ElMessage, ElMessageBox } from 'element-plus';
import { useAdminLocale } from '../../composables/useAdminLocale';
import api from '../../api';
import LogoUrlField from '../../components/LogoUrlField.vue';
import AdminSubNav from '../../components/AdminSubNav.vue';
import {
  getBuiltinCountry,
  resolveCountryCode,
  type BuiltinCountry,
} from '../../data/builtinCountries';

const route = useRoute();
const { t } = useAdminLocale();

const matchId = computed(() => String(route.params.matchId ?? ''));

interface SelectionRow {
  id: string;
  teamCode: string;
  rank: number;
  teamZh: string;
  teamEn: string;
  odds: string;
  oddsVersion: string;
  status: string;
  logoUrl: string | null;
  editOdds: number;
  editCountryCode: string;
  editLogoUrl: string;
}

const loading = ref(false);
const saving = ref(false);
const savingRowId = ref<string | null>(null);
const meta = ref({
  leagueZh: '',
  leagueEn: '',
  leagueCode: '',
  titleZh: '',
  titleEn: '',
  titleMs: '',
  status: 'DRAFT',
  expectedCanonicalCount: null as number | null,
  playerVisible: true,
  playerHiddenReason: null as string | null,
});
const selections = ref<SelectionRow[]>([]);

const addVisible = ref(false);
const addForm = ref({
  countryCode: '',
  teamCode: '',
  teamZh: '',
  teamEn: '',
  logoUrl: '',
  odds: 10,
});

function applyCountry(target: {
  countryCode: string;
  teamCode: string;
  teamZh: string;
  teamEn: string;
}, country: BuiltinCountry) {
  target.countryCode = country.code;
  target.teamCode = country.code;
  target.teamZh = country.nameZh;
  target.teamEn = country.nameEn;
}

function onAddCountryPick(country: BuiltinCountry) {
  applyCountry(addForm.value, country);
}

async function load() {
  if (!matchId.value) return;
  loading.value = true;
  try {
    const { data } = await api.get(`/admin/outrights/${matchId.value}`);
    const payload = data.data as {
      leagueZh: string;
      leagueEn: string;
      leagueCode: string;
      titleZh: string;
      titleEn: string;
      titleMs: string;
      status: string;
      expectedCanonicalCount: number | null;
      playerVisible: boolean;
      playerHiddenReason: string | null;
      selections: Array<SelectionRow & { logoUrl?: string | null }>;
    };
    meta.value = {
      leagueZh: payload.leagueZh,
      leagueEn: payload.leagueEn,
      leagueCode: payload.leagueCode,
      titleZh: payload.titleZh ?? '',
      titleEn: payload.titleEn ?? '',
      titleMs: payload.titleMs ?? '',
      status: payload.status,
      expectedCanonicalCount: payload.expectedCanonicalCount,
      playerVisible: payload.playerVisible,
      playerHiddenReason: payload.playerHiddenReason,
    };
    selections.value = payload.selections.map((s) => ({
      ...s,
      logoUrl: s.logoUrl ?? null,
      editOdds: Number(s.odds),
      editCountryCode: resolveCountryCode(s.teamCode, s.logoUrl ?? null),
      editLogoUrl: s.logoUrl ?? '',
    }));
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.load_failed'));
  } finally {
    loading.value = false;
  }
}

watch(matchId, load, { immediate: true });

async function saveMeta() {
  saving.value = true;
  try {
    await api.put(`/admin/outrights/${matchId.value}`, {
      status: meta.value.status,
      titleZh: meta.value.titleZh,
      titleEn: meta.value.titleEn,
      titleMs: meta.value.titleMs,
    });
    ElMessage.success(t('msg.saved'));
    await load();
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.save_failed'));
  } finally {
    saving.value = false;
  }
}

async function saveAllOdds() {
  const invalid = selections.value.find((s) => !s.editOdds || s.editOdds <= 1);
  if (invalid) {
    ElMessage.warning(t('outright.err_odds_min'));
    return;
  }
  saving.value = true;
  try {
    await api.put(`/admin/outrights/${matchId.value}/odds`, {
      updates: selections.value.map((s) => ({
        selectionId: s.id,
        odds: s.editOdds,
      })),
    });
    ElMessage.success(t('msg.outright_odds_saved'));
    await load();
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.save_failed'));
  } finally {
    saving.value = false;
  }
}

async function submitAdd() {
  if (!addForm.value.countryCode) {
    ElMessage.warning(t('outright.err_country'));
    return;
  }
  const country = getBuiltinCountry(addForm.value.countryCode);
  if (!country) {
    ElMessage.warning(t('outright.err_country'));
    return;
  }
  saving.value = true;
  try {
    await api.post(`/admin/outrights/${matchId.value}/selections`, {
      teamCode: country.code,
      teamZh: country.nameZh,
      teamEn: country.nameEn,
      logoUrl: addForm.value.logoUrl.trim() || undefined,
      odds: addForm.value.odds,
    });
    ElMessage.success(t('msg.saved'));
    addVisible.value = false;
    addForm.value = { countryCode: '', teamCode: '', teamZh: '', teamEn: '', logoUrl: '', odds: 10 };
    await load();
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.save_failed'));
  } finally {
    saving.value = false;
  }
}

async function removeSelection(row: SelectionRow) {
  try {
    await ElMessageBox.confirm(
      t('outright.confirm_remove', { name: row.teamZh || row.teamCode }),
      { type: 'warning' },
    );
  } catch {
    return;
  }
  loading.value = true;
  try {
    await api.delete(`/admin/outrights/${matchId.value}/selections/${row.id}`);
    ElMessage.success(t('msg.saved'));
    await load();
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.save_failed'));
  } finally {
    loading.value = false;
  }
}

const playerHiddenTip = computed(() => {
  const key = meta.value.playerHiddenReason;
  if (!key) return '';
  return t(`outright.hidden_reason.${key}`);
});

const teamCountLabel = computed(() => {
  const total = meta.value.expectedCanonicalCount;
  if (total != null) {
    return t('outright.team_count', { n: selections.value.length, total });
  }
  return t('outright.team_count_open', { n: selections.value.length });
});

const isPublished = computed(() => meta.value.status === 'PUBLISHED');

const leagueLabel = computed(() => {
  const name = meta.value.leagueZh || meta.value.leagueEn;
  const code = meta.value.leagueCode;
  if (name && code) return `${name} (${code})`;
  return name || code || '';
});

async function saveMetaWithStatus(status: 'DRAFT' | 'PUBLISHED') {
  meta.value.status = status;
  await saveMeta();
}

function rowDisplayName(row: SelectionRow, field: 'zh' | 'en') {
  const picked = getBuiltinCountry(row.editCountryCode);
  if (picked && row.editCountryCode !== resolveCountryCode(row.teamCode, row.logoUrl)) {
    return field === 'zh' ? picked.nameZh : picked.nameEn;
  }
  return field === 'zh' ? row.teamZh : row.teamEn;
}

function rowDisplayCode(row: SelectionRow) {
  const picked = getBuiltinCountry(row.editCountryCode);
  if (picked && row.editCountryCode !== resolveCountryCode(row.teamCode, row.logoUrl)) {
    return picked.code;
  }
  return row.teamCode;
}

function isRowDirty(row: SelectionRow) {
  const countryDirty =
    row.editCountryCode !== resolveCountryCode(row.teamCode, row.logoUrl);
  const logoDirty = (row.editLogoUrl || '').trim() !== (row.logoUrl || '').trim();
  const oddsDirty = row.editOdds !== Number(row.odds);
  return countryDirty || logoDirty || oddsDirty;
}

function onRowCountryPick(row: SelectionRow, country: BuiltinCountry) {
  row.editCountryCode = country.code;
}

function onRowLogoChange(row: SelectionRow, url: string) {
  row.editLogoUrl = url;
  const code = resolveCountryCode(row.editCountryCode || row.teamCode, url);
  if (code) row.editCountryCode = code;
}

function onAddLogoChange(url: string) {
  addForm.value.logoUrl = url;
  const code = resolveCountryCode(addForm.value.countryCode, url);
  if (code) addForm.value.countryCode = code;
}

function onAddLogoPick(country: BuiltinCountry) {
  onAddCountryPick(country);
}

async function saveRow(row: SelectionRow) {
  if (!isRowDirty(row)) return;
  if (!row.editOdds || row.editOdds <= 1) {
    ElMessage.warning(t('outright.err_odds_min'));
    return;
  }

  savingRowId.value = row.id;
  try {
    const country = getBuiltinCountry(row.editCountryCode);
    const countryDirty =
      row.editCountryCode !== resolveCountryCode(row.teamCode, row.logoUrl);
    const logoDirty = (row.editLogoUrl || '').trim() !== (row.logoUrl || '').trim();

    if (countryDirty || logoDirty) {
      if (!country) {
        ElMessage.warning(t('outright.err_country'));
        return;
      }
      await api.patch(`/admin/outrights/${matchId.value}/selections/${row.id}`, {
        teamCode: country.code,
        teamZh: country.nameZh,
        teamEn: country.nameEn,
        logoUrl: row.editLogoUrl.trim() || undefined,
      });
    }

    if (row.editOdds !== Number(row.odds)) {
      await api.put(`/admin/outrights/${matchId.value}/odds`, {
        updates: [{ selectionId: row.id, odds: row.editOdds }],
      });
    }

    ElMessage.success(t('msg.saved'));
    await load();
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.save_failed'));
  } finally {
    savingRowId.value = null;
  }
}
</script>

<template>
  <div class="event-editor" v-loading="loading">
    <AdminSubNav
      :title="t('outright.section.edit')"
      :subtitle="`#${matchId}`"
    />

    <el-alert
      v-if="!meta.playerVisible"
      type="warning"
      :closable="false"
      show-icon
      class="player-alert"
      :title="t('outright.player_hidden_title')"
      :description="playerHiddenTip"
    />

    <section class="panel settings-panel">
      <div class="settings-top">
        <div class="title-fields">
          <el-form label-width="88px" size="small" @submit.prevent="saveMeta">
            <el-form-item :label="t('outright.field.title_zh')">
              <el-input v-model="meta.titleZh" @keyup.enter="saveMeta" />
            </el-form-item>
            <el-form-item :label="t('outright.field.title_en')">
              <el-input v-model="meta.titleEn" @keyup.enter="saveMeta" />
            </el-form-item>
            <el-form-item :label="t('outright.field.title_ms')">
              <el-input v-model="meta.titleMs" @keyup.enter="saveMeta" />
            </el-form-item>
          </el-form>
        </div>
        <div class="settings-actions">
          <el-button size="small" :loading="saving" @click="saveMeta">
            {{ t('common.save') }}
          </el-button>
          <el-button
            v-if="!isPublished"
            type="primary"
            size="small"
            :loading="saving"
            @click="saveMetaWithStatus('PUBLISHED')"
          >
            {{ t('outright.btn.publish') }}
          </el-button>
          <el-button
            v-else
            size="small"
            :loading="saving"
            @click="saveMetaWithStatus('DRAFT')"
          >
            {{ t('outright.btn.unpublish') }}
          </el-button>
        </div>
      </div>
      <p v-if="leagueLabel" class="league-meta">
        <span class="league-meta-k">{{ t('outright.field.league') }}</span>
        {{ leagueLabel }}
      </p>
    </section>

    <section class="panel teams-panel">
      <div class="panel-head compact">
        <span class="panel-title">{{ t('outright.section.teams') }} · {{ teamCountLabel }}</span>
        <el-button type="primary" plain size="small" @click="addVisible = true">
          {{ t('outright.btn.add_team') }}
        </el-button>
      </div>

      <div class="table-wrap">
        <el-table :data="selections" stripe size="small" empty-text="—">
          <el-table-column prop="rank" :label="t('outright.col.rank')" width="72" align="center" />
          <el-table-column :label="t('outright.col.country')" min-width="340">
            <template #default="{ row }">
              <LogoUrlField
                :model-value="row.editLogoUrl"
                compact
                :team-code="row.editCountryCode || row.teamCode"
                @update:model-value="onRowLogoChange(row, $event)"
                @pick="onRowCountryPick(row, $event)"
              />
            </template>
          </el-table-column>
          <el-table-column :label="t('outright.col.team_zh')" min-width="120">
            <template #default="{ row }">{{ rowDisplayName(row, 'zh') }}</template>
          </el-table-column>
          <el-table-column :label="t('outright.col.team_en')" min-width="140">
            <template #default="{ row }">{{ rowDisplayName(row, 'en') }}</template>
          </el-table-column>
          <el-table-column :label="t('outright.col.code')" width="88">
            <template #default="{ row }">{{ rowDisplayCode(row) }}</template>
          </el-table-column>
          <el-table-column :label="t('outright.col.odds')" width="160" align="right">
            <template #default="{ row }">
              <el-input-number
                v-model="row.editOdds"
                :min="1.01"
                :step="0.05"
                :precision="2"
                controls-position="right"
                size="small"
                style="width: 130px"
              />
            </template>
          </el-table-column>
          <el-table-column :label="t('common.actions')" width="120" align="center" fixed="right">
            <template #default="{ row }">
              <el-button
                link
                type="primary"
                :loading="savingRowId === row.id"
                :disabled="!isRowDirty(row) || (!!savingRowId && savingRowId !== row.id)"
                @click="saveRow(row)"
              >
                {{ t('common.save') }}
              </el-button>
              <el-button
                link
                type="danger"
                :disabled="!!savingRowId"
                @click="removeSelection(row)"
              >
                {{ t('common.delete') }}
              </el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>

      <div class="panel-foot compact">
        <el-button size="small" @click="load">{{ t('common.reset') }}</el-button>
        <el-button type="primary" size="small" :loading="saving" @click="saveAllOdds">
          {{ t('outright.btn.save_odds') }}
        </el-button>
      </div>
    </section>

    <el-dialog v-model="addVisible" :title="t('outright.btn.add_team')" width="520px">
      <el-form label-width="100px">
        <el-form-item :label="t('outright.col.country')" required>
          <LogoUrlField
            :model-value="addForm.logoUrl"
            :team-code="addForm.countryCode"
            @update:model-value="onAddLogoChange"
            @pick="onAddLogoPick"
          />
        </el-form-item>
        <el-form-item v-if="addForm.teamCode" :label="t('outright.col.code')">
          <span class="readonly-field">{{ addForm.teamCode }}</span>
        </el-form-item>
        <el-form-item v-if="addForm.teamZh" :label="t('outright.col.team_zh')">
          <span class="readonly-field">{{ addForm.teamZh }}</span>
        </el-form-item>
        <el-form-item v-if="addForm.teamEn" :label="t('outright.col.team_en')">
          <span class="readonly-field">{{ addForm.teamEn }}</span>
        </el-form-item>
        <el-form-item :label="t('outright.col.odds')">
          <el-input-number v-model="addForm.odds" :min="1.01" :step="0.05" :precision="2" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="addVisible = false">{{ t('common.cancel') }}</el-button>
        <el-button type="primary" :loading="saving" @click="submitAdd">{{ t('common.confirm') }}</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<style scoped>
.event-editor {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow: auto;
}

.player-alert {
  flex-shrink: 0;
  margin-bottom: 0;
}

.player-alert :deep(.el-alert__content) {
  padding: 4px 0;
}

.panel {
  background: #111;
  border: 1px solid #252525;
  border-radius: 8px;
  padding: 10px 12px;
  flex-shrink: 0;
}

.teams-panel {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.settings-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.title-fields {
  flex: 1;
  min-width: 0;
}

.league-meta {
  margin: 6px 0 0;
  font-size: 11px;
  color: #555;
  line-height: 1.4;
}

.league-meta-k {
  color: #444;
  margin-right: 4px;
}

.settings-actions {
  display: flex;
  flex-shrink: 0;
  gap: 6px;
}

.panel-head.compact {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
}

.panel-title {
  font-size: 13px;
  font-weight: 700;
  color: #ccc;
}

.panel-foot.compact {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid #222;
}

.teams-panel .panel-foot.compact {
  margin-top: auto;
}

.table-wrap {
  flex: 1;
  min-height: 80px;
  overflow: auto;
}

.readonly-field {
  font-size: 13px;
  color: #aaa;
}

.panel {
  border-color: var(--border);
  background: #ffffff;
  box-shadow: var(--shadow);
}

.league-meta,
.league-meta-k,
.readonly-field {
  color: var(--text-muted);
}

.panel-title {
  color: var(--text);
}

.panel-foot.compact {
  border-top-color: var(--border-soft);
}

@media (max-width: 760px) {
  .settings-top,
  .panel-head.compact,
  .panel-foot.compact {
    align-items: stretch;
    flex-direction: column;
  }
}
</style>
