<script setup lang="ts">
import { ref, computed, watch } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import type { TableInstance } from 'element-plus';
import { useAdminLocale } from '../composables/useAdminLocale';
import api from '../api';
import AdminTableEmpty from '../components/AdminTableEmpty.vue';

const { t, localeTag } = useAdminLocale();

type StoredContentType = 'BANNER' | 'NOTICE' | 'TICKER';
type AdminTab = 'BANNER' | 'ANNOUNCEMENT';
type ContentStatus = 'DRAFT' | 'ACTIVE' | 'INACTIVE';

interface TranslationForm {
  locale: string;
  title: string;
  body: string;
  imageUrl: string;
}

interface ContentItem {
  id: string;
  contentType: StoredContentType;
  sortOrder: number;
  status: ContentStatus;
  linkType: string | null;
  linkTarget: string | null;
  startTime: string | null;
  endTime: string | null;
  previewTitle: string;
  previewImageUrl: string | null;
  playerVisible: boolean;
  playerHiddenReason: string | null;
  translations: TranslationForm[];
}

const ADMIN_TABS: AdminTab[] = ['BANNER', 'ANNOUNCEMENT'];
const LOCALES = ['zh-CN', 'en-US', 'ms-MY'] as const;

const activeType = ref<AdminTab>('BANNER');
const filterStatus = ref<ContentStatus | ''>('');
const loading = ref(false);
const saving = ref(false);
const items = ref<ContentItem[]>([]);
const tableRef = ref<TableInstance>();
const selectedRows = ref<ContentItem[]>([]);

const hasSelection = computed(() => selectedRows.value.length > 0);

const dialogVisible = ref(false);
const editingId = ref<string | null>(null);
const editingContentType = ref<StoredContentType>('NOTICE');

const form = ref({
  sortOrder: 0,
  status: 'DRAFT' as ContentStatus,
  linkType: '' as '' | 'ROUTE' | 'URL',
  linkTarget: '',
  startTime: '' as string,
  endTime: '' as string,
  translations: emptyTranslations(),
});

function emptyTranslations(): TranslationForm[] {
  return LOCALES.map((locale) => ({
    locale,
    title: '',
    body: '',
    imageUrl: '',
  }));
}

function localeLabel(code: string) {
  const key = `content.locale.${code}`;
  const label = t(key);
  return label === key ? code : label;
}

function statusLabel(status: string) {
  const key = `content.status.${status}`;
  const label = t(key);
  return label === key ? status : label;
}

function statusTagType(status: string) {
  if (status === 'ACTIVE') return 'success';
  if (status === 'DRAFT') return 'info';
  return 'warning';
}

function hiddenTip(reason: string | null) {
  if (!reason) return '';
  const key = `content.hidden_reason.${reason}`;
  const label = t(key);
  return label === key ? reason : label;
}

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

const isBanner = computed(() => activeType.value === 'BANNER');
const isAnnouncement = computed(() => activeType.value === 'ANNOUNCEMENT');
const dialogTitle = computed(() =>
  editingId.value ? t('content.dialog.edit') : t('content.dialog.create'),
);

async function load() {
  loading.value = true;
  try {
    const { data } = await api.get('/admin/contents', {
      params: {
        type: activeType.value,
        status: filterStatus.value || undefined,
      },
    });
    items.value = data.data ?? [];
    selectedRows.value = [];
    tableRef.value?.clearSelection();
  } 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([activeType, filterStatus], () => {
  selectedRows.value = [];
  tableRef.value?.clearSelection();
  void load();
});

function onSelectionChange(rows: ContentItem[]) {
  selectedRows.value = rows;
}

async function runBatch(
  action: (row: ContentItem) => Promise<void>,
  confirmKey?: string,
) {
  const rows = [...selectedRows.value];
  if (!rows.length) return;

  if (confirmKey) {
    try {
      await ElMessageBox.confirm(t(confirmKey, { n: rows.length }), { type: 'warning' });
    } catch {
      return;
    }
  }

  saving.value = true;
  let ok = 0;
  let fail = 0;
  try {
    for (const row of rows) {
      try {
        await action(row);
        ok += 1;
      } catch {
        fail += 1;
      }
    }
    if (fail === 0) {
      ElMessage.success(t('content.batch.all_ok', { n: ok }));
    } else {
      ElMessage.warning(t('content.batch.partial', { ok, fail }));
    }
    await load();
  } finally {
    saving.value = false;
  }
}

function batchEnable() {
  void runBatch(
    (row) => api.patch(`/admin/contents/${row.id}/status`, { status: 'ACTIVE' }),
    'content.confirm_batch_enable',
  );
}

function batchDisable() {
  void runBatch(
    (row) => api.patch(`/admin/contents/${row.id}/status`, { status: 'INACTIVE' }),
    'content.confirm_batch_disable',
  );
}

function batchDelete() {
  void runBatch(
    (row) => api.delete(`/admin/contents/${row.id}`),
    'content.confirm_batch_delete',
  );
}

function resetForm() {
  form.value = {
    sortOrder: items.value.length + 1,
    status: 'DRAFT',
    linkType: '',
    linkTarget: '',
    startTime: '',
    endTime: '',
    translations: emptyTranslations(),
  };
}

function openCreate() {
  editingId.value = null;
  resetForm();
  dialogVisible.value = true;
}

function openEdit(row: ContentItem) {
  editingId.value = row.id;
  editingContentType.value = row.contentType;
  const byLocale = new Map(row.translations.map((tr) => [tr.locale, tr]));
  form.value = {
    sortOrder: row.sortOrder,
    status: row.status,
    linkType: (row.linkType as '' | 'ROUTE' | 'URL') || '',
    linkTarget: row.linkTarget ?? '',
    startTime: row.startTime ? row.startTime.slice(0, 19) : '',
    endTime: row.endTime ? row.endTime.slice(0, 19) : '',
    translations: LOCALES.map((locale) => {
      const tr = byLocale.get(locale);
      return {
        locale,
        title: tr?.title ?? '',
        body: tr?.body ?? '',
        imageUrl: tr?.imageUrl ?? '',
      };
    }),
  };
  dialogVisible.value = true;
}

function buildPayload() {
  const contentType: StoredContentType = editingId.value
    ? editingContentType.value
    : isBanner.value
      ? 'BANNER'
      : 'NOTICE';

  return {
    contentType,
    sortOrder: form.value.sortOrder,
    status: form.value.status,
    linkType: isBanner.value && form.value.linkType ? form.value.linkType : null,
    linkTarget:
      isBanner.value && form.value.linkType ? form.value.linkTarget.trim() : null,
    startTime: form.value.startTime || null,
    endTime: form.value.endTime || null,
    translations: form.value.translations.map((tr) => ({
      locale: tr.locale,
      title: tr.title.trim() || undefined,
      body: tr.body.trim() || undefined,
      imageUrl: tr.imageUrl.trim() || undefined,
    })),
  };
}

async function submitForm() {
  saving.value = true;
  try {
    const payload = buildPayload();
    if (editingId.value) {
      const { contentType: _type, ...updateBody } = payload;
      await api.put(`/admin/contents/${editingId.value}`, updateBody);
    } else {
      await api.post('/admin/contents', payload);
    }
    ElMessage.success(t('msg.saved'));
    dialogVisible.value = false;
    await load();
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string; message?: string | string[] } } };
    const msg = err.response?.data?.error
      ?? (Array.isArray(err.response?.data?.message)
        ? err.response?.data?.message.join(', ')
        : err.response?.data?.message)
      ?? t('msg.save_failed');
    ElMessage.error(String(msg));
  } finally {
    saving.value = false;
  }
}

async function setStatus(row: ContentItem, status: ContentStatus) {
  saving.value = true;
  try {
    await api.patch(`/admin/contents/${row.id}/status`, { status });
    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 removeItem(row: ContentItem) {
  try {
    await ElMessageBox.confirm(
      t('content.confirm_delete', { title: row.previewTitle || row.id }),
      { type: 'warning' },
    );
  } catch {
    return;
  }
  saving.value = true;
  try {
    await api.delete(`/admin/contents/${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 {
    saving.value = false;
  }
}

void load();
</script>

<template>
  <div class="admin-list-page contents-page">
    <el-card class="filter-card" shadow="never">
      <el-tabs v-model="activeType" class="type-tabs">
        <el-tab-pane
          v-for="tp in ADMIN_TABS"
          :key="tp"
          :label="t(`content.type.${tp}`)"
          :name="tp"
        />
      </el-tabs>
      <p v-if="isAnnouncement" class="type-hint">{{ t('content.hint.announcement') }}</p>
      <el-form inline class="filter-row">
        <el-form-item :label="t('common.status')">
          <el-select v-model="filterStatus" clearable style="width: 140px">
            <el-option :label="t('common.all')" value="" />
            <el-option
              v-for="st in ['DRAFT', 'ACTIVE', 'INACTIVE']"
              :key="st"
              :label="statusLabel(st)"
              :value="st"
            />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" size="small" @click="load">{{ t('common.search') }}</el-button>
          <el-button type="primary" plain size="small" @click="openCreate">
            {{ t('content.btn.create') }}
          </el-button>
        </el-form-item>
      </el-form>
    </el-card>

    <el-card v-loading="loading" class="data-card" shadow="never">
      <div v-if="hasSelection" class="table-toolbar">
        <span class="batch-hint">{{ t('content.batch.selected', { n: selectedRows.length }) }}</span>
        <el-button size="small" :disabled="saving" @click="batchEnable">
          {{ t('content.batch.enable') }}
        </el-button>
        <el-button size="small" :disabled="saving" @click="batchDisable">
          {{ t('content.batch.disable') }}
        </el-button>
        <el-button size="small" type="danger" :disabled="saving" @click="batchDelete">
          {{ t('content.batch.delete') }}
        </el-button>
      </div>
      <div class="table-wrap">
        <el-table
          ref="tableRef"
          :data="items"
          row-key="id"
          stripe
          size="small"
          @selection-change="onSelectionChange"
        >
          <template #empty>
            <AdminTableEmpty />
          </template>
          <el-table-column type="selection" width="44" :selectable="() => !saving" />
          <el-table-column prop="sortOrder" :label="t('content.col.sort')" width="64" align="center" />
          <el-table-column v-if="isBanner" :label="t('content.col.preview')" width="88" align="center">
            <template #default="{ row }">
              <img
                v-if="row.previewImageUrl"
                :src="row.previewImageUrl"
                alt=""
                class="thumb"
              />
              <span v-else class="thumb-empty">—</span>
            </template>
          </el-table-column>
          <el-table-column :label="t('content.col.title')" min-width="160">
            <template #default="{ row }">
              <span class="preview-title">{{ row.previewTitle || '—' }}</span>
              <p v-if="!row.playerVisible && row.playerHiddenReason" class="hidden-tip">
                {{ hiddenTip(row.playerHiddenReason) }}
              </p>
            </template>
          </el-table-column>
          <el-table-column :label="t('common.status')" width="96" align="center">
            <template #default="{ row }">
              <el-tag size="small" :type="statusTagType(row.status)" effect="dark">
                {{ statusLabel(row.status) }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column :label="t('content.col.player_visible')" width="88" align="center">
            <template #default="{ row }">
              <el-tag size="small" :type="row.playerVisible ? 'success' : 'warning'" effect="plain">
                {{ row.playerVisible ? t('common.yes') : t('common.no') }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column :label="t('content.col.schedule')" min-width="140">
            <template #default="{ row }">
              <span class="schedule-line">{{ formatTime(row.startTime) }}</span>
              <span class="schedule-sep">→</span>
              <span class="schedule-line">{{ formatTime(row.endTime) }}</span>
            </template>
          </el-table-column>
          <el-table-column v-if="isBanner" :label="t('content.col.link')" min-width="120">
            <template #default="{ row }">
              <template v-if="row.linkType">
                {{ row.linkType }} · {{ row.linkTarget || '—' }}
              </template>
              <span v-else>—</span>
            </template>
          </el-table-column>
          <el-table-column :label="t('common.actions')" width="200" align="center" fixed="right">
            <template #default="{ row }">
              <el-button link type="primary" @click="openEdit(row)">
                {{ t('common.edit') }}
              </el-button>
              <el-button
                v-if="row.status !== 'ACTIVE'"
                link
                type="success"
                :disabled="saving"
                @click="setStatus(row, 'ACTIVE')"
              >
                {{ t('content.btn.enable') }}
              </el-button>
              <el-button
                v-else
                link
                type="warning"
                :disabled="saving"
                @click="setStatus(row, 'INACTIVE')"
              >
                {{ t('content.btn.disable') }}
              </el-button>
              <el-button link type="danger" :disabled="saving" @click="removeItem(row)">
                {{ t('common.delete') }}
              </el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </el-card>

    <el-dialog v-model="dialogVisible" :title="dialogTitle" width="640px" destroy-on-close>
      <el-form label-width="96px" size="small">
        <el-form-item :label="t('content.col.sort')">
          <el-input-number v-model="form.sortOrder" :min="0" :step="1" />
        </el-form-item>
        <el-form-item :label="t('common.status')">
          <el-select v-model="form.status" style="width: 160px">
            <el-option
              v-for="st in ['DRAFT', 'ACTIVE', 'INACTIVE']"
              :key="st"
              :label="statusLabel(st)"
              :value="st"
            />
          </el-select>
        </el-form-item>
        <template v-if="isBanner">
          <el-form-item :label="t('content.field.link_type')">
            <el-select v-model="form.linkType" clearable style="width: 160px">
              <el-option :label="t('content.link.none')" value="" />
              <el-option label="ROUTE" value="ROUTE" />
              <el-option label="URL" value="URL" />
            </el-select>
          </el-form-item>
          <el-form-item v-if="form.linkType" :label="t('content.field.link_target')">
            <el-input
              v-model="form.linkTarget"
              :placeholder="form.linkType === 'ROUTE' ? '/football' : 'https://'"
            />
          </el-form-item>
        </template>
        <el-form-item :label="t('content.field.start_time')">
          <el-date-picker
            v-model="form.startTime"
            type="datetime"
            value-format="YYYY-MM-DDTHH:mm:ss"
            clearable
            style="width: 100%"
          />
        </el-form-item>
        <el-form-item :label="t('content.field.end_time')">
          <el-date-picker
            v-model="form.endTime"
            type="datetime"
            value-format="YYYY-MM-DDTHH:mm:ss"
            clearable
            style="width: 100%"
          />
        </el-form-item>

        <div v-for="tr in form.translations" :key="tr.locale" class="locale-block">
          <div class="locale-head">{{ localeLabel(tr.locale) }}</div>
          <el-form-item :label="t('content.field.title')">
            <el-input v-model="tr.title" :placeholder="t('content.field.title_ph')" />
          </el-form-item>
          <el-form-item
            v-if="isBanner"
            :label="t('content.field.image_url')"
            :required="form.status === 'ACTIVE'"
          >
            <el-input v-model="tr.imageUrl" placeholder="/uploads/banners/welcome.svg" />
          </el-form-item>
          <el-form-item
            :label="isAnnouncement ? t('content.field.announce_text') : t('content.field.body')"
            :required="isAnnouncement && form.status === 'ACTIVE'"
          >
            <el-input v-model="tr.body" type="textarea" :rows="isAnnouncement ? 2 : 3" />
          </el-form-item>
        </div>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
        <el-button type="primary" :loading="saving" @click="submitForm">
          {{ t('common.save') }}
        </el-button>
      </template>
    </el-dialog>
  </div>
</template>

<style scoped>
.contents-page .type-tabs :deep(.el-tabs__header) {
  margin-bottom: 12px;
}

.table-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 10px 12px;
  border-bottom: 1px solid #222;
  flex-shrink: 0;
}

.batch-hint {
  font-size: 12px;
  color: #888;
  margin-right: 4px;
}

.type-hint {
  margin: 0 0 8px;
  font-size: 12px;
  color: #666;
  line-height: 1.5;
}

.filter-row {
  margin-top: 4px;
}

.thumb {
  width: 56px;
  height: 32px;
  object-fit: cover;
  border-radius: 4px;
  background: #222;
}

.thumb-empty {
  color: #555;
  font-size: 12px;
}

.preview-title {
  font-size: 13px;
  color: #ccc;
}

.hidden-tip {
  margin: 4px 0 0;
  font-size: 11px;
  color: #c9a227;
}

.schedule-line {
  font-size: 11px;
  color: #888;
}

.schedule-sep {
  margin: 0 4px;
  color: #555;
  font-size: 11px;
}

.locale-block {
  margin-top: 12px;
  padding: 10px 12px;
  border: 1px solid #252525;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.02);
}

.locale-head {
  font-size: 12px;
  font-weight: 700;
  color: #888;
  margin-bottom: 8px;
}
</style>
