<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { ElMessage } from 'element-plus';
import { useAdminLocale } from '../composables/useAdminLocale';
import { useSmokeTestsAllowed } from '../composables/useSmokeTestsAllowed';
import api from '../api';
import AdminTableEmpty from '../components/AdminTableEmpty.vue';

const { t, locale, localeTag } = useAdminLocale();
const router = useRouter();
const { allowed: smokeTestsAllowed, ensureLoaded: ensureSmokeTestsAllowed } = useSmokeTestsAllowed();

type SuiteInfo = { id: string; name: string; description: string; caseCount: number };
type CaseMeta = { id: string; suite: string; name: string; uatRef?: string };
type CaseResult = CaseMeta & {
  status: 'PASS' | 'FAIL' | 'SKIP';
  durationMs: number;
  stepCount?: number;
  message?: string;
  error?: string;
  details?: string[];
};
type RunSummary = {
  runId: string;
  startedAt: string;
  finishedAt: string;
  durationMs: number;
  total: number;
  passed: number;
  failed: number;
  skipped: number;
  suites: string[];
  results: CaseResult[];
};

const suites = ref<SuiteInfo[]>([]);
const selectedSuites = ref<string[]>([]);
const running = ref(false);
const lastRun = ref<RunSummary | null>(null);
const filterStatus = ref('');

const suiteName = (id: string) => suites.value.find((s) => s.id === id)?.name ?? id;

const filteredResults = computed(() => {
  const rows = lastRun.value?.results ?? [];
  if (!filterStatus.value) return rows;
  return rows.filter((r) => r.status === filterStatus.value);
});

const passRate = computed(() => {
  if (!lastRun.value?.total) return 0;
  return Math.round((lastRun.value.passed / lastRun.value.total) * 100);
});

const runLogText = computed(() => (lastRun.value ? formatRunLog(lastRun.value) : ''));

function formatCaseHeader(row: CaseResult) {
  const parts = [
    `[${row.status}]`,
    row.id,
    suiteName(row.suite),
    row.name,
    row.uatRef ? `UAT:${row.uatRef}` : null,
    row.stepCount ? `${row.stepCount} steps` : null,
    `${row.durationMs}ms`,
    row.error || row.message || '',
  ].filter(Boolean);
  return parts.join(' | ');
}

function formatCaseBlock(row: CaseResult) {
  const lines = [formatCaseHeader(row)];
  if (row.details?.length) {
    lines.push(...row.details.map((d) => `    ${d.replace(/\n/g, '\n    ')}`));
  }
  return lines.join('\n');
}

function formatCaseLine(row: CaseResult) {
  return formatCaseBlock(row);
}

function formatRunLog(run: RunSummary) {
  const lines = [
    '=== Smoke Test Report ===',
    `Run ID: ${run.runId}`,
    `Started: ${run.startedAt}`,
    `Finished: ${run.finishedAt}`,
    `Duration: ${run.durationMs}ms`,
    `Summary: pass=${run.passed}, fail=${run.failed}, skip=${run.skipped}, total=${run.total}`,
    `Suites: ${run.suites.join(', ')}`,
    '',
    '--- Cases ---',
    ...run.results.map((row) => formatCaseBlock(row)),
  ];
  return lines.join('\n\n');
}

async function copyText(text: string) {
  if (!text) return;
  try {
    if (navigator.clipboard?.writeText) {
      await navigator.clipboard.writeText(text);
    } else {
      const ta = document.createElement('textarea');
      ta.value = text;
      ta.style.position = 'fixed';
      ta.style.left = '-9999px';
      document.body.appendChild(ta);
      ta.select();
      document.execCommand('copy');
      document.body.removeChild(ta);
    }
    ElMessage.success(t('smoke.msg.copy_ok'));
  } catch {
    ElMessage.error(t('smoke.msg.copy_failed'));
  }
}

async function loadMeta() {
  const { data } = await api.get('/admin/smoke-tests/suites');
  suites.value = data.data?.suites ?? [];
  if (data.data?.lastRun) lastRun.value = data.data.lastRun;
  if (!selectedSuites.value.length) {
    selectedSuites.value = suites.value.map((s) => s.id);
  }
}

async function runTests() {
  running.value = true;
  try {
    const { data } = await api.post('/admin/smoke-tests/run', {
      suites: selectedSuites.value.length ? selectedSuites.value : undefined,
    });
    lastRun.value = data.data as RunSummary;
    if (lastRun.value.failed > 0) {
      ElMessage.warning(t('smoke.msg.has_failures', { n: lastRun.value.failed }));
    } else {
      ElMessage.success(t('smoke.msg.all_passed', { n: lastRun.value.passed }));
    }
  } catch (e: unknown) {
    const msg = (e as { response?: { data?: { error?: string } } })?.response?.data?.error;
    ElMessage.error(msg || t('smoke.msg.run_failed'));
  } finally {
    running.value = false;
  }
}

function formatTime(v: string) {
  return new Date(v).toLocaleString(localeTag.value);
}

function statusTagType(status: string) {
  if (status === 'PASS') return 'success';
  if (status === 'FAIL') return 'danger';
  return 'info';
}

onMounted(async () => {
  await ensureSmokeTestsAllowed();
  if (!smokeTestsAllowed.value) {
    router.replace('/');
    return;
  }
  await loadMeta();
});
</script>

<template>
  <div class="admin-list-page smoke-page">
    <el-card class="intro-card" shadow="never">
      <p class="intro-text">{{ t('smoke.intro') }}</p>
      <ul class="intro-list">
        <li>{{ t('smoke.intro_rule') }}</li>
        <li>{{ t('smoke.intro_db') }}</li>
        <li>{{ t('smoke.intro_bet_flow') }}</li>
        <li>{{ t('smoke.intro_note') }}</li>
      </ul>
    </el-card>

    <el-card class="filter-card" shadow="never">
      <el-form inline>
        <el-form-item :label="t('smoke.field.suites')">
          <el-select
            v-model="selectedSuites"
            multiple
            collapse-tags
            collapse-tags-tooltip
            :placeholder="t('smoke.ph.suites')"
            style="min-width: 320px"
          >
            <el-option
              v-for="s in suites"
              :key="s.id"
              :label="`${s.name} (${s.caseCount})`"
              :value="s.id"
            />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" :loading="running" @click="runTests">
            {{ t('smoke.btn.run') }}
          </el-button>
        </el-form-item>
      </el-form>
    </el-card>

    <el-card v-if="lastRun" class="data-card summary-card" shadow="never">
      <div class="summary-head">
        <div>
          <div class="summary-title">{{ t('smoke.last_run') }}</div>
          <div class="summary-meta">
            {{ formatTime(lastRun.startedAt) }} · {{ lastRun.durationMs }}ms · {{ lastRun.runId }}
          </div>
        </div>
        <div class="summary-actions">
          <div class="summary-stats">
            <el-tag type="success">{{ t('smoke.stat.pass') }} {{ lastRun.passed }}</el-tag>
            <el-tag type="danger">{{ t('smoke.stat.fail') }} {{ lastRun.failed }}</el-tag>
            <el-tag>{{ t('smoke.stat.total') }} {{ lastRun.total }}</el-tag>
            <el-tag type="warning">{{ passRate }}%</el-tag>
          </div>
          <el-button size="small" @click="copyText(runLogText)">{{ t('smoke.btn.copy_all') }}</el-button>
        </div>
      </div>
    </el-card>

    <el-card v-if="lastRun" class="data-card" shadow="never">
      <div class="table-head">
        <span class="table-title">{{ t('smoke.results_title') }}</span>
        <el-select v-model="filterStatus" clearable :placeholder="t('common.all')" style="width: 120px">
          <el-option :label="t('smoke.status.PASS')" value="PASS" />
          <el-option :label="t('smoke.status.FAIL')" value="FAIL" />
        </el-select>
      </div>
      <div class="table-wrap">
        <el-table :data="filteredResults" stripe row-key="id">
          <template #empty>
            <AdminTableEmpty />
          </template>
          <el-table-column type="expand" width="44">
            <template #default="{ row }">
              <div v-if="row.details?.length" class="case-details">
                <pre>{{ row.details.join('\n\n') }}</pre>
              </div>
              <span v-else class="case-details-empty">{{ t('smoke.no_steps') }}</span>
            </template>
          </el-table-column>
          <el-table-column type="index" :label="t('common.seq')" width="55" align="center" />
          <el-table-column prop="id" :label="t('smoke.col.id')" width="88" />
          <el-table-column :label="t('smoke.col.suite')" width="120">
            <template #default="{ row }">{{ suiteName(row.suite) }}</template>
          </el-table-column>
          <el-table-column prop="name" :label="t('smoke.col.name')" min-width="180" />
          <el-table-column prop="uatRef" :label="t('smoke.col.uat')" width="88">
            <template #default="{ row }">{{ row.uatRef ?? '—' }}</template>
          </el-table-column>
          <el-table-column :label="t('common.status')" width="96">
            <template #default="{ row }">
              <el-tag :type="statusTagType(row.status)" size="small">
                {{ t(`smoke.status.${row.status}`) }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column :label="t('smoke.col.steps')" width="72" align="center">
            <template #default="{ row }">{{ row.stepCount ?? '—' }}</template>
          </el-table-column>
          <el-table-column :label="t('smoke.col.duration')" width="96" align="right">
            <template #default="{ row }">{{ row.durationMs }}ms</template>
          </el-table-column>
          <el-table-column :label="t('smoke.col.message')" min-width="200" show-overflow-tooltip>
            <template #default="{ row }">
              <span :class="{ 'fail-msg': row.status === 'FAIL' }">{{ row.error || row.message || '—' }}</span>
            </template>
          </el-table-column>
          <el-table-column :label="t('common.actions')" width="88" fixed="right">
            <template #default="{ row }">
              <el-button link type="primary" size="small" @click="copyText(formatCaseBlock(row))">
                {{ t('smoke.btn.copy_one') }}
              </el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <div class="log-panel">
        <div class="log-head">
          <span class="table-title">{{ t('smoke.log_title') }}</span>
          <el-button size="small" @click="copyText(runLogText)">{{ t('smoke.btn.copy_all') }}</el-button>
        </div>
        <el-input
          type="textarea"
          class="log-textarea"
          :model-value="runLogText"
          readonly
          :rows="18"
          resize="vertical"
        />
      </div>
    </el-card>

    <el-card v-else class="data-card empty-card" shadow="never">
      <p>{{ t('smoke.empty') }}</p>
    </el-card>
  </div>
</template>

<style scoped>
.intro-text {
  margin: 0 0 8px;
  color: #666;
  line-height: 1.5;
}

.intro-list {
  margin: 0;
  padding-left: 18px;
  color: #888;
  font-size: 13px;
  line-height: 1.6;
}

.summary-head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 12px;
  align-items: flex-start;
}

.summary-title {
  font-size: 15px;
  font-weight: 700;
}

.summary-meta {
  font-size: 12px;
  color: #888;
  margin-top: 4px;
}

.summary-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
}

.summary-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
}

.log-panel {
  margin-top: 16px;
  border-top: 1px solid var(--el-border-color-lighter);
  padding-top: 12px;
}

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

.log-textarea :deep(textarea) {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 12px;
  line-height: 1.5;
}

.table-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}

.table-title {
  font-weight: 700;
}

.fail-msg {
  color: var(--el-color-danger);
}

.case-details {
  padding: 8px 12px 12px 48px;
}

.case-details pre {
  margin: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 12px;
  line-height: 1.55;
  white-space: pre-wrap;
  word-break: break-word;
  color: #444;
}

.case-details-empty {
  padding: 8px 12px 12px 48px;
  color: #999;
  font-size: 13px;
}

.empty-card {
  text-align: center;
  color: #888;
  padding: 24px 0;
}

.intro-text,
.intro-list,
.summary-meta,
.empty-card,
.case-details-empty {
  color: var(--text-muted);
}

.summary-title,
.table-title {
  color: var(--text);
}

.case-details {
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  background: #fbfaf7;
}

.case-details pre {
  color: var(--text);
}

@media (max-width: 760px) {
  .summary-actions,
  .summary-stats,
  .table-head,
  .log-head {
    align-items: flex-start;
    flex-direction: column;
  }
}
</style>
