<script setup lang="ts">
/**
 * 通用资源表单：按 resourceSchemas.fields 渲染，支持 media/switch/select。
 * JSON 模式仅作高级兜底；复杂资源应走专用页。
 */
import { computed, reactive, ref } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { useToast } from '@wot-ui/ui'
import AppNavbar from '@/components/layout/AppNavbar.vue'
import AppPageShell from '@/components/layout/AppPageShell.vue'
import AdminMediaPicker from '../../components/AdminMediaPicker.vue'
import AdminFormField from '../../components/AdminFormField.vue'
import { useAuth } from '@/composables/useAuth'
import { useAppMode } from '@/composables/useAppMode'
import { adminCreate, adminGet, adminUpdate } from '@/api'
import { getResourceSchema, type SchemaField } from '../../config/resourceSchemas'

const toast = useToast()
const { isAuthenticated } = useAuth()
const { canEnterAdmin } = useAppMode()

const resource = ref('')
const mode = ref<'create' | 'edit'>('create')
const id = ref('')
const loading = ref(false)
const submitting = ref(false)
const jsonMode = ref(false)
const form = reactive<Record<string, unknown>>({})
const rawJson = ref('{}')

const schema = computed(() => getResourceSchema(resource.value))
const fields = computed(() => schema.value.fields.filter(f => !f.editOnly || mode.value === 'edit'))
const pageTitle = computed(() => {
  const label = schema.value.title || resource.value
  return mode.value === 'create' ? `新建${label}` : `编辑${label}`
})

function guardAdmin() {
  if (!isAuthenticated() || !canEnterAdmin.value) {
    uni.reLaunch({ url: '/pages/mine/index' })
    return false
  }
  return true
}

function initEmpty() {
  Object.keys(form).forEach(k => delete form[k])
  fields.value.forEach((f) => {
    if (f.type === 'switch') form[f.key] = 1
    else if (f.type === 'number' || f.type === 'rating') form[f.key] = f.type === 'rating' ? 5 : 0
    else form[f.key] = ''
  })
  rawJson.value = '{}'
}

function fillFromRecord(data: Record<string, unknown>) {
  Object.keys(form).forEach(k => delete form[k])
  fields.value.forEach((f) => {
    const v = data[f.key]
    if (f.type === 'switch') form[f.key] = v === true || v === 1 || v === '1' ? 1 : 0
    else if (f.type === 'number' || f.type === 'rating') form[f.key] = Number(v ?? 0)
    else if (f.key === 'config' && typeof v === 'object') form[f.key] = JSON.stringify(v, null, 2)
    else form[f.key] = v ?? ''
  })
  // 保留未声明字段以便 JSON 模式完整编辑
  rawJson.value = JSON.stringify(data, null, 2)
}

async function load() {
  if (!resource.value || !guardAdmin()) return
  loading.value = true
  try {
    if (mode.value === 'edit' && id.value) {
      const data = await adminGet(resource.value, id.value) as Record<string, unknown>
      fillFromRecord(data)
    }
    else {
      initEmpty()
    }
  }
  catch (e: unknown) {
    toast.error(e instanceof Error ? e.message : '加载失败')
  }
  finally {
    loading.value = false
  }
}

onLoad((q) => {
  resource.value = String(q?.resource || '')
  mode.value = (q?.mode === 'edit' ? 'edit' : 'create') as 'create' | 'edit'
  id.value = String(q?.id || '')
  // 无字段的资源强制 JSON
  if (!getResourceSchema(resource.value).fields.length) jsonMode.value = true
})

onShow(load)

function buildPayload(): Record<string, unknown> {
  if (jsonMode.value) {
    try {
      return JSON.parse(rawJson.value || '{}') as Record<string, unknown>
    }
    catch {
      throw new Error('JSON 格式不正确')
    }
  }
  const payload: Record<string, unknown> = {}
  fields.value.forEach((f: SchemaField) => {
    let v = form[f.key]
    if (f.type === 'number' || f.type === 'rating') v = Number(v ?? 0)
    if (f.type === 'switch') v = v ? 1 : 0
    if (f.key === 'config' && typeof v === 'string') {
      try { v = JSON.parse(v) }
      catch { /* 保持字符串，后端可自行处理 */ }
    }
    payload[f.key] = v
  })
  return payload
}

const onSubmit = async () => {
  submitting.value = true
  try {
    const payload = buildPayload()
    if (mode.value === 'edit' && id.value) await adminUpdate(resource.value, id.value, payload)
    else await adminCreate(resource.value, payload)
    toast.success('已保存')
    setTimeout(() => uni.navigateBack(), 400)
  }
  catch (e: unknown) {
    toast.error(e instanceof Error ? e.message : '保存失败')
  }
  finally {
    submitting.value = false
  }
}

function selectLabel(f: SchemaField) {
  const opts = f.options || []
  const hit = opts.find(o => String(o.value) === String(form[f.key]))
  return hit?.label || '请选择'
}
</script>

<template>
  <AppPageShell admin>
    <AppNavbar :title="pageTitle" show-back />
    <view class="page-pad">
      <view class="admin-card form-card">
        <template v-if="!jsonMode && fields.length">
          <template v-for="f in fields" :key="f.key">
            <AdminFormField v-if="f.type === 'text' || f.type === 'number'" :label="f.label">
              <wd-input
                :model-value="String(form[f.key] ?? '')"
                :placeholder="f.placeholder || f.label"
                :disabled="f.readonly"
                clearable
                @update:model-value="(v: string | number) => form[f.key] = v"
              />
            </AdminFormField>
            <AdminFormField v-else-if="f.type === 'textarea'" :label="f.label">
              <wd-textarea
                :model-value="String(form[f.key] ?? '')"
                :placeholder="f.placeholder || f.label"
                @update:model-value="(v: string) => form[f.key] = v"
              />
            </AdminFormField>
            <AdminMediaPicker
              v-else-if="f.type === 'media'"
              :model-value="String(form[f.key] ?? '')"
              :label="f.label"
              @update:model-value="(v: string) => form[f.key] = v"
            />
            <view v-else-if="f.type === 'switch'" class="switch-row">
              <text>{{ f.label }}</text>
              <wd-switch
                :model-value="!!form[f.key]"
                @change="(v: boolean) => form[f.key] = v ? 1 : 0"
              />
            </view>
            <view v-else-if="f.type === 'rating'" class="rating-row">
              <text class="label">{{ f.label }}</text>
              <view class="stars">
                <text
                  v-for="n in 5"
                  :key="n"
                  class="star"
                  :class="{ on: Number(form[f.key]) >= n }"
                  @click="form[f.key] = n"
                >
                  ★
                </text>
              </view>
            </view>
            <wd-picker
              v-else-if="f.type === 'select' && f.options"
              :columns="[f.options.map(o => ({ label: o.label, value: o.value }))]"
              @confirm="({ value }: { value: unknown[] }) => { form[f.key] = (value?.[0] as { value?: unknown })?.value ?? value?.[0] }"
            >
              <view class="picker-row">
                <text class="label">{{ f.label }}</text>
                <text class="val">{{ selectLabel(f) }}</text>
              </view>
            </wd-picker>
          </template>
        </template>
        <template v-else>
          <AdminFormField label="JSON">
            <wd-textarea v-model="rawJson" placeholder="{}" />
          </AdminFormField>
        </template>

        <view class="actions">
          <wd-button size="small" plain @click="jsonMode = !jsonMode">
            {{ jsonMode ? '表单模式' : 'JSON 模式' }}
          </wd-button>
        </view>

        <wd-button
          block
          type="primary"
          :loading="submitting"
          custom-style="margin-top:24rpx;background:#d4b383;border-color:#d4b383;"
          @click="onSubmit"
        >
          保存
        </wd-button>
      </view>
      <wd-loading v-if="loading" />
    </view>
  </AppPageShell>
</template>

<style scoped lang="scss">
.page-pad { padding: 24rpx 32rpx 80rpx; }
.actions { display: flex; flex-wrap: wrap; gap: 12rpx; margin-top: 16rpx; }
.switch-row, .picker-row, .rating-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20rpx 0;
  color: rgb(var(--art-text));
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.label { font-size: 28rpx; }
.val { font-size: 26rpx; color: rgba(255, 255, 255, 0.65); }
.stars { display: flex; gap: 8rpx; }
.star { font-size: 36rpx; color: rgba(255, 255, 255, 0.25); }
.star.on { color: rgb(var(--art-accent)); }
</style>
