<script lang="ts" setup>
import { computed, reactive, ref, watch } from 'vue';

import { Page } from '@vben/common-ui';
import { useAccessStore } from '@vben/stores';

import {
  Button,
  Card,
  Input,
  InputNumber,
  Select,
  Space,
  Spin,
  Switch,
  Table,
  Tabs,
  TabPane,
  Tag,
  TextArea,
  message,
} from 'antdv-next';

import {
  getVoiceRoomRocketConfig,
  getVoiceRoomRocketLevelConfigs,
  getVoiceRoomRocketRewardConfigs,
  saveVoiceRoomRocketConfig,
  saveVoiceRoomRocketLevelConfigs,
  saveVoiceRoomRocketRewardConfigs,
} from '#/api/legacy/resident-activity';
import { getAllowedSysOrigins } from '#/views/system/shared';

defineOptions({ name: 'ResidentVoiceRoomRocketPage' });

const RIYADH_TIMEZONE = 'Asia/Riyadh';
const DEFAULT_MAX_LEVEL = 6;

type LevelRow = {
  enabled: boolean;
  id?: number | string;
  level: number;
  needEnergy: number;
  progressBarUrl: string;
  rocketAnimationUrl: string;
  rocketIconUrl: string;
  shakeThresholdPercent: string;
  sort: number;
};

type RewardRow = {
  enabled: boolean;
  expireDays?: null | number;
  id?: number | string;
  localKey: string;
  level: number;
  rewardAmount: number;
  rewardCover: string;
  rewardItemId?: null | number | string;
  rewardName: string;
  rewardScene: string;
  rewardType: string;
  sort: number;
  weight: number;
};

const accessStore = useAccessStore();
const sysOriginOptions = computed(() => {
  const options = getAllowedSysOrigins(accessStore.accessCodes || []);
  return options.length > 0 ? options : getAllowedSysOrigins([]);
});

const selectedSysOrigin = ref('');
const activeTab = ref('config');
const rewardLevel = ref(1);

const configLoading = ref(false);
const levelLoading = ref(false);
const rewardLoading = ref(false);
const configSaving = ref(false);
const levelSaving = ref(false);
const rewardSaving = ref(false);

const configForm = reactive({
  broadcastDurationSeconds: 7,
  configured: false,
  enabled: false,
  energyRuleJsonText: '{}',
  id: '',
  inRoomRewardDelaySeconds: 10,
  maxLevel: DEFAULT_MAX_LEVEL,
  rankingTopLimit: 100,
  rewardRecordKeepDays: 35,
  ruleTextText: '{}',
  timezone: RIYADH_TIMEZONE,
  updateTime: '',
});

const levelRows = ref<LevelRow[]>([]);
const rewardRows = ref<RewardRow[]>([]);

const sceneOptions = [
  { label: '贡献第一', value: 'TOP1' },
  { label: '点火人', value: 'IGNITE' },
  { label: '在房用户', value: 'IN_ROOM' },
];

const rewardTypeOptions = [
  { label: '金币', value: 'GOLD' },
  { label: '坐骑', value: 'MOUNT' },
  { label: '头像框', value: 'AVATAR_FRAME' },
  { label: '气泡', value: 'CHAT_BUBBLE' },
  { label: 'VIP', value: 'VIP_CARD' },
  { label: '礼物', value: 'GIFT' },
  { label: '徽章', value: 'BADGE' },
];

const levelOptions = computed(() =>
  Array.from({ length: configForm.maxLevel || DEFAULT_MAX_LEVEL }, (_, index) => ({
    label: `Lv.${index + 1}`,
    value: index + 1,
  })),
);

const statusMeta = computed(() => {
  if (!configForm.configured) {
    return { color: 'warning', text: '未配置' };
  }
  return configForm.enabled
    ? { color: 'success', text: '已启用' }
    : { color: 'default', text: '已关闭' };
});

const levelColumns = [
  { dataIndex: 'level', key: 'level', title: '等级', width: 90 },
  { dataIndex: 'needEnergy', key: 'needEnergy', title: '所需能量', width: 160 },
  { dataIndex: 'shakeThresholdPercent', key: 'shakeThresholdPercent', title: '晃动阈值(%)', width: 160 },
  { dataIndex: 'rocketIconUrl', key: 'rocketIconUrl', title: '火箭图标', width: 260 },
  { dataIndex: 'rocketAnimationUrl', key: 'rocketAnimationUrl', title: '发射动画', width: 260 },
  { dataIndex: 'progressBarUrl', key: 'progressBarUrl', title: '进度条资源', width: 260 },
  { dataIndex: 'enabled', key: 'enabled', title: '启用', width: 90 },
  { dataIndex: 'sort', key: 'sort', title: '排序', width: 100 },
];

const rewardColumns = [
  { dataIndex: 'rewardScene', key: 'rewardScene', title: '奖励场景', width: 150 },
  { dataIndex: 'rewardType', key: 'rewardType', title: '奖励类型', width: 150 },
  { dataIndex: 'rewardItemId', key: 'rewardItemId', title: '资源ID', width: 170 },
  { dataIndex: 'rewardName', key: 'rewardName', title: '奖励名称', width: 180 },
  { dataIndex: 'rewardCover', key: 'rewardCover', title: '封面URL', width: 220 },
  { dataIndex: 'rewardAmount', key: 'rewardAmount', title: '数量/金币/天数', width: 150 },
  { dataIndex: 'expireDays', key: 'expireDays', title: '有效天数', width: 130 },
  { dataIndex: 'weight', key: 'weight', title: '权重', width: 110 },
  { dataIndex: 'enabled', key: 'enabled', title: '启用', width: 90 },
  { dataIndex: 'sort', key: 'sort', title: '排序', width: 100 },
  { dataIndex: 'actions', key: 'actions', title: '操作', width: 100 },
];

function createDefaultLevel(level: number): LevelRow {
  return {
    enabled: true,
    level,
    needEnergy: level * 100,
    progressBarUrl: '',
    rocketAnimationUrl: '',
    rocketIconUrl: '',
    shakeThresholdPercent: '95.0000',
    sort: level,
  };
}

function stringifyJSON(value: unknown) {
  if (value === null || value === undefined || value === '') {
    return '{}';
  }
  if (typeof value === 'string') {
    return value.trim() || '{}';
  }
  return JSON.stringify(value, null, 2);
}

function parseJSONText(value: string, label: string) {
  const raw = String(value || '').trim();
  if (!raw) {
    return {};
  }
  try {
    return JSON.parse(raw);
  } catch {
    message.warning(`${label} 必须是合法 JSON`);
    return undefined;
  }
}

function toNumber(value: unknown, fallback = 0) {
  const parsed = Number(value);
  return Number.isFinite(parsed) ? parsed : fallback;
}

function toOptionalNumber(value: unknown) {
  if (value === null || value === undefined || value === '') {
    return undefined;
  }
  const parsed = Number(value);
  return Number.isFinite(parsed) ? parsed : undefined;
}

function toOptionalString(value: unknown) {
  const text = String(value ?? '').trim();
  return text || undefined;
}

function normalizeConfig(value: Record<string, any> | null | undefined) {
  const next = value || {};
  configForm.broadcastDurationSeconds = toNumber(
    next.broadcastDurationSeconds,
    7,
  );
  configForm.configured = Boolean(next.configured);
  configForm.enabled = Boolean(next.enabled);
  configForm.energyRuleJsonText = stringifyJSON(next.energyRuleJson);
  configForm.id = String(next.id || '');
  configForm.inRoomRewardDelaySeconds = toNumber(
    next.inRoomRewardDelaySeconds,
    10,
  );
  configForm.maxLevel = toNumber(next.maxLevel, DEFAULT_MAX_LEVEL);
  configForm.rankingTopLimit = toNumber(next.rankingTopLimit, 100);
  configForm.rewardRecordKeepDays = toNumber(next.rewardRecordKeepDays, 35);
  configForm.ruleTextText = stringifyJSON(next.ruleText);
  configForm.timezone = RIYADH_TIMEZONE;
  configForm.updateTime = String(next.updateTime || '');
}

function normalizeLevelRows(rows: Array<Record<string, any>> | undefined) {
  const source = Array.isArray(rows) ? rows : [];
  const byLevel = new Map<number, Record<string, any>>();
  source.forEach((item) => {
    byLevel.set(toNumber(item.level), item);
  });
  levelRows.value = Array.from({ length: DEFAULT_MAX_LEVEL }, (_, index) => {
    const level = index + 1;
    const row = byLevel.get(level) || {};
    return {
      ...createDefaultLevel(level),
      enabled: row.enabled === undefined ? true : Boolean(row.enabled),
      id: row.id,
      needEnergy: toNumber(row.needEnergy, level * 100),
      progressBarUrl: String(row.progressBarUrl || ''),
      rocketAnimationUrl: String(row.rocketAnimationUrl || ''),
      rocketIconUrl: String(row.rocketIconUrl || ''),
      shakeThresholdPercent: String(row.shakeThresholdPercent || '95.0000'),
      sort: toNumber(row.sort, level),
    };
  });
}

function normalizeRewardRows(rows: Array<Record<string, any>> | undefined) {
  rewardRows.value = (Array.isArray(rows) ? rows : []).map((row, index) => ({
    enabled: row.enabled === undefined ? true : Boolean(row.enabled),
    expireDays: toOptionalNumber(row.expireDays) ?? null,
    id: row.id,
    level: toNumber(row.level, rewardLevel.value),
    localKey: `${row.id || 'new'}-${index}-${Date.now()}`,
    rewardAmount: toNumber(row.rewardAmount, 1),
    rewardCover: String(row.rewardCover || ''),
    rewardItemId: row.rewardItemId ?? null,
    rewardName: String(row.rewardName || ''),
    rewardScene: String(row.rewardScene || 'TOP1'),
    rewardType: String(row.rewardType || 'GOLD'),
    sort: toNumber(row.sort, index + 1),
    weight: toNumber(row.weight, 1),
  }));
}

async function loadConfig() {
  if (!selectedSysOrigin.value) {
    return;
  }
  configLoading.value = true;
  try {
    const result = await getVoiceRoomRocketConfig(selectedSysOrigin.value);
    normalizeConfig(result);
  } finally {
    configLoading.value = false;
  }
}

async function loadLevels() {
  if (!selectedSysOrigin.value) {
    return;
  }
  levelLoading.value = true;
  try {
    const result = await getVoiceRoomRocketLevelConfigs(selectedSysOrigin.value);
    normalizeLevelRows(result);
  } finally {
    levelLoading.value = false;
  }
}

async function loadRewards() {
  if (!selectedSysOrigin.value) {
    return;
  }
  rewardLoading.value = true;
  try {
    const result = await getVoiceRoomRocketRewardConfigs({
      level: rewardLevel.value,
      sysOrigin: selectedSysOrigin.value,
    });
    normalizeRewardRows(result);
  } finally {
    rewardLoading.value = false;
  }
}

async function loadAll() {
  await Promise.all([loadConfig(), loadLevels(), loadRewards()]);
}

async function saveConfig() {
  const energyRuleJson = parseJSONText(
    configForm.energyRuleJsonText,
    '能量规则',
  );
  if (energyRuleJson === undefined) {
    return;
  }
  const ruleText = parseJSONText(configForm.ruleTextText, '规则说明');
  if (ruleText === undefined) {
    return;
  }
  configSaving.value = true;
  try {
    const result = await saveVoiceRoomRocketConfig({
      broadcastDurationSeconds: configForm.broadcastDurationSeconds,
      enabled: configForm.enabled,
      energyRuleJson,
      inRoomRewardDelaySeconds: configForm.inRoomRewardDelaySeconds,
      maxLevel: DEFAULT_MAX_LEVEL,
      rankingTopLimit: configForm.rankingTopLimit,
      rewardRecordKeepDays: configForm.rewardRecordKeepDays,
      ruleText,
      sysOrigin: selectedSysOrigin.value,
      timezone: RIYADH_TIMEZONE,
    });
    normalizeConfig(result);
    message.success('保存成功');
  } finally {
    configSaving.value = false;
  }
}

async function saveLevels() {
  levelSaving.value = true;
  try {
    const result = await saveVoiceRoomRocketLevelConfigs({
      levels: levelRows.value.map((row) => ({
        enabled: row.enabled,
        id: row.id,
        level: row.level,
        needEnergy: toNumber(row.needEnergy, row.level * 100),
        progressBarUrl: row.progressBarUrl,
        rocketAnimationUrl: row.rocketAnimationUrl,
        rocketIconUrl: row.rocketIconUrl,
        shakeThresholdPercent: row.shakeThresholdPercent,
        sort: toNumber(row.sort, row.level),
      })),
      sysOrigin: selectedSysOrigin.value,
    });
    normalizeLevelRows(result);
    message.success('保存成功');
  } finally {
    levelSaving.value = false;
  }
}

function addRewardRow(scene = 'TOP1') {
  rewardRows.value.push({
    enabled: true,
    expireDays: null,
    level: rewardLevel.value,
    localKey: `new-${Date.now()}-${rewardRows.value.length}`,
    rewardAmount: 1,
    rewardCover: '',
    rewardItemId: null,
    rewardName: scene === 'TOP1' ? '金币' : '',
    rewardScene: scene,
    rewardType: 'GOLD',
    sort: rewardRows.value.length + 1,
    weight: 1,
  });
}

function removeRewardRow(index: number) {
  rewardRows.value.splice(index, 1);
}

function handleRewardTypeChange(row: Record<string, any>) {
  if (row.rewardType === 'GOLD') {
    row.rewardItemId = null;
    row.expireDays = null;
    if (!row.rewardName) {
      row.rewardName = '金币';
    }
  }
}

function validateRewards() {
  for (const row of rewardRows.value) {
    if (!row.rewardScene) {
      message.warning('请选择奖励场景');
      return false;
    }
    if (!row.rewardType) {
      message.warning('请选择奖励类型');
      return false;
    }
    if (!String(row.rewardName || '').trim()) {
      message.warning('请输入奖励名称');
      return false;
    }
    if (row.rewardType !== 'GOLD' && !String(row.rewardItemId || '').trim()) {
      message.warning('非金币奖励必须填写资源ID');
      return false;
    }
  }
  return true;
}

async function saveRewards() {
  if (!validateRewards()) {
    return;
  }
  rewardSaving.value = true;
  try {
    const result = await saveVoiceRoomRocketRewardConfigs({
      level: rewardLevel.value,
      rewards: rewardRows.value.map((row) => ({
        enabled: row.enabled,
        expireDays: toOptionalNumber(row.expireDays),
        id: row.id,
        level: rewardLevel.value,
        rewardAmount: toNumber(row.rewardAmount, 1),
        rewardCover: row.rewardCover,
        rewardItemId:
          row.rewardType === 'GOLD' ? undefined : toOptionalString(row.rewardItemId),
        rewardName: row.rewardName.trim(),
        rewardScene: row.rewardScene,
        rewardType: row.rewardType,
        sort: toNumber(row.sort, 1),
        weight: toNumber(row.weight, 1),
      })),
      sysOrigin: selectedSysOrigin.value,
    });
    normalizeRewardRows(result);
    message.success('保存成功');
  } finally {
    rewardSaving.value = false;
  }
}

watch(
  sysOriginOptions,
  (options) => {
    if (!selectedSysOrigin.value && options[0]?.value) {
      selectedSysOrigin.value = String(options[0].value);
    }
  },
  { immediate: true },
);

watch(
  selectedSysOrigin,
  () => {
    void loadAll();
  },
  { immediate: true },
);

watch(rewardLevel, () => {
  void loadRewards();
});
</script>

<template>
  <Page title="火箭">
    <div class="voice-room-rocket-page">
      <Card>
        <Space wrap>
          <span>系统</span>
          <Select
            v-model:value="selectedSysOrigin"
            :options="sysOriginOptions"
            style="width: 180px"
          />
          <Tag :color="statusMeta.color">{{ statusMeta.text }}</Tag>
          <Tag color="processing">利雅得时间每日 00:00 重置</Tag>
          <span v-if="configForm.updateTime" class="muted-text">
            更新时间：{{ configForm.updateTime }}
          </span>
        </Space>
      </Card>

      <Tabs v-model:active-key="activeTab">
        <TabPane key="config" tab="基础配置">
          <Spin :spinning="configLoading">
            <Card>
              <div class="config-grid">
                <label class="field-row">
                  <span>启用火箭</span>
                  <Switch v-model:checked="configForm.enabled" />
                </label>
                <label class="field-row">
                  <span>活动时区</span>
                  <Input
                    v-model:value="configForm.timezone"
                    class="field-control"
                    disabled
                  />
                </label>
                <label class="field-row">
                  <span>最大等级</span>
                  <InputNumber
                    v-model:value="configForm.maxLevel"
                    :min="1"
                    :max="6"
                    :precision="0"
                    class="field-control"
                    disabled
                  />
                </label>
                <label class="field-row">
                  <span>榜单人数</span>
                  <InputNumber
                    v-model:value="configForm.rankingTopLimit"
                    :min="1"
                    :max="100"
                    :precision="0"
                    class="field-control"
                  />
                </label>
                <label class="field-row">
                  <span>发奖记录保留天数</span>
                  <InputNumber
                    v-model:value="configForm.rewardRecordKeepDays"
                    :min="1"
                    :precision="0"
                    class="field-control"
                  />
                </label>
                <label class="field-row">
                  <span>发射广播秒数</span>
                  <InputNumber
                    v-model:value="configForm.broadcastDurationSeconds"
                    :min="1"
                    :precision="0"
                    class="field-control"
                  />
                </label>
                <label class="field-row">
                  <span>在房奖励延迟秒数</span>
                  <InputNumber
                    v-model:value="configForm.inRoomRewardDelaySeconds"
                    :min="1"
                    :precision="0"
                    class="field-control"
                  />
                </label>
                <label class="field-row field-wide">
                  <span>能量规则 JSON</span>
                  <TextArea
                    v-model:value="configForm.energyRuleJsonText"
                    :rows="4"
                    class="field-control"
                  />
                </label>
                <label class="field-row field-wide">
                  <span>规则说明 JSON</span>
                  <TextArea
                    v-model:value="configForm.ruleTextText"
                    :rows="4"
                    class="field-control"
                  />
                </label>
              </div>

              <div class="actions">
                <Space>
                  <Button @click="loadConfig">刷新</Button>
                  <Button type="primary" :loading="configSaving" @click="saveConfig">
                    保存基础配置
                  </Button>
                </Space>
              </div>
            </Card>
          </Spin>
        </TabPane>

        <TabPane key="levels" tab="等级进度">
          <Card>
            <Table
              :columns="levelColumns"
              :data-source="levelRows"
              :loading="levelLoading"
              :pagination="false"
              :scroll="{ x: 1420 }"
              row-key="level"
            >
              <template #bodyCell="{ column, record }">
                <template v-if="column.key === 'level'">
                  <Tag color="blue">Lv.{{ record.level }}</Tag>
                </template>
                <template v-else-if="column.key === 'needEnergy'">
                  <InputNumber
                    v-model:value="record.needEnergy"
                    :min="1"
                    :precision="0"
                    class="table-number"
                  />
                </template>
                <template v-else-if="column.key === 'shakeThresholdPercent'">
                  <Input
                    v-model:value="record.shakeThresholdPercent"
                    class="table-input"
                  />
                </template>
                <template v-else-if="column.key === 'rocketIconUrl'">
                  <Input v-model:value="record.rocketIconUrl" class="table-input" />
                </template>
                <template v-else-if="column.key === 'rocketAnimationUrl'">
                  <Input
                    v-model:value="record.rocketAnimationUrl"
                    class="table-input"
                  />
                </template>
                <template v-else-if="column.key === 'progressBarUrl'">
                  <Input v-model:value="record.progressBarUrl" class="table-input" />
                </template>
                <template v-else-if="column.key === 'enabled'">
                  <Switch v-model:checked="record.enabled" />
                </template>
                <template v-else-if="column.key === 'sort'">
                  <InputNumber
                    v-model:value="record.sort"
                    :min="1"
                    :precision="0"
                    class="table-number"
                  />
                </template>
              </template>
            </Table>

            <div class="actions">
              <Space>
                <Button @click="loadLevels">刷新</Button>
                <Button type="primary" :loading="levelSaving" @click="saveLevels">
                  保存等级进度
                </Button>
              </Space>
            </div>
          </Card>
        </TabPane>

        <TabPane key="rewards" tab="奖励配置">
          <Card>
            <Space class="reward-toolbar" wrap>
              <span>等级</span>
              <Select
                v-model:value="rewardLevel"
                :options="levelOptions"
                style="width: 120px"
              />
              <Button @click="loadRewards">刷新</Button>
              <Button @click="addRewardRow('TOP1')">添加贡献第一</Button>
              <Button @click="addRewardRow('IGNITE')">添加点火人</Button>
              <Button @click="addRewardRow('IN_ROOM')">添加在房用户</Button>
              <Button type="primary" :loading="rewardSaving" @click="saveRewards">
                保存当前等级奖励
              </Button>
            </Space>

            <Table
              :columns="rewardColumns"
              :data-source="rewardRows"
              :loading="rewardLoading"
              :pagination="false"
              :scroll="{ x: 1660 }"
              row-key="localKey"
            >
              <template #bodyCell="{ column, record, index }">
                <template v-if="column.key === 'rewardScene'">
                  <Select
                    v-model:value="record.rewardScene"
                    :options="sceneOptions"
                    class="table-select"
                  />
                </template>
                <template v-else-if="column.key === 'rewardType'">
                  <Select
                    v-model:value="record.rewardType"
                    :options="rewardTypeOptions"
                    class="table-select"
                    @change="() => handleRewardTypeChange(record)"
                  />
                </template>
                <template v-else-if="column.key === 'rewardItemId'">
                  <Input
                    v-model:value="record.rewardItemId"
                    :disabled="record.rewardType === 'GOLD'"
                    class="table-input-small"
                  />
                </template>
                <template v-else-if="column.key === 'rewardName'">
                  <Input v-model:value="record.rewardName" class="table-input-small" />
                </template>
                <template v-else-if="column.key === 'rewardCover'">
                  <Input v-model:value="record.rewardCover" class="table-input" />
                </template>
                <template v-else-if="column.key === 'rewardAmount'">
                  <InputNumber
                    v-model:value="record.rewardAmount"
                    :min="1"
                    :precision="0"
                    class="table-number"
                  />
                </template>
                <template v-else-if="column.key === 'expireDays'">
                  <InputNumber
                    v-model:value="record.expireDays"
                    :disabled="record.rewardType === 'GOLD'"
                    :min="0"
                    :precision="0"
                    class="table-number"
                  />
                </template>
                <template v-else-if="column.key === 'weight'">
                  <InputNumber
                    v-model:value="record.weight"
                    :min="0"
                    :precision="0"
                    class="table-number"
                  />
                </template>
                <template v-else-if="column.key === 'enabled'">
                  <Switch v-model:checked="record.enabled" />
                </template>
                <template v-else-if="column.key === 'sort'">
                  <InputNumber
                    v-model:value="record.sort"
                    :min="1"
                    :precision="0"
                    class="table-number"
                  />
                </template>
                <template v-else-if="column.key === 'actions'">
                  <Button danger size="small" @click="removeRewardRow(index)">
                    删除
                  </Button>
                </template>
              </template>
            </Table>

            <div class="reward-summary">
              <Tag v-for="scene in sceneOptions" :key="scene.value">
                {{ scene.label }}：
                {{
                  rewardRows.filter((item) => item.rewardScene === scene.value).length
                }}
              </Tag>
              <Tag v-for="type in rewardTypeOptions" :key="type.value">
                {{ type.label }}：
                {{ rewardRows.filter((item) => item.rewardType === type.value).length }}
              </Tag>
            </div>
          </Card>
        </TabPane>
      </Tabs>
    </div>
  </Page>
</template>

<style scoped>
.voice-room-rocket-page {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.config-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 16px;
}

.field-row {
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: 13px;
  color: #4b5563;
}

.field-wide {
  grid-column: 1 / -1;
}

.field-control {
  width: 100%;
}

.actions {
  display: flex;
  justify-content: flex-end;
  margin-top: 16px;
}

.muted-text {
  color: #8c8c8c;
}

.reward-toolbar {
  margin-bottom: 16px;
}

.reward-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
}

.table-input {
  width: 240px;
}

.table-input-small,
.table-select {
  width: 140px;
}

.table-number {
  width: 110px;
}
</style>
