<template>
  <div class="app-container">
    <el-card>
      <template #header>
        <div class="card-header">
          <span>数据还原管理</span>
          <el-alert
             title="警告：数据还原是高风险操作，请谨慎执行。建议还原前先进行备份。"
             type="warning"
             show-icon
             :closable="false"
             style="margin-left: 20px; flex: 1"
          />
        </div>
      </template>

      <!-- Step 1: Select Backup -->
      <div v-show="activeStep === 0">
        <h3>第一步：选择备份文件</h3>
        
        <div class="header-actions" style="margin-bottom: 10px; display: flex; justify-content: flex-end;">
           <el-upload
             class="upload-demo"
             action="#"
             :show-file-list="false"
             :http-request="handleUpload"
             accept=".zip"
           >
             <el-button type="primary" :loading="uploading">上传备份文件</el-button>
           </el-upload>
        </div>

        <el-table :data="backupList" style="width: 100%" v-loading="loadingList" highlight-current-row @current-change="handleBackupSelect">
          <el-table-column width="50">
             <template #default="scope">
                <el-radio v-model="selectedBackupId" :label="scope.row.id">&nbsp;</el-radio>
             </template>
          </el-table-column>
          <el-table-column prop="filename" label="文件名" min-width="200" />
          <el-table-column prop="created_at" label="备份时间" width="180">
             <template #default="scope">
                {{ formatDate(scope.row.created_at) }}
             </template>
          </el-table-column>
          <el-table-column prop="backup_type" label="类型" width="100">
            <template #default="scope">
              <el-tag :type="scope.row.backup_type === 'AUTO' ? 'info' : 'success'">
                {{ scope.row.backup_type === 'AUTO' ? '自动' : '手动' }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="file_size" label="大小" width="120">
            <template #default="scope">
              {{ formatSize(scope.row.file_size) }}
            </template>
          </el-table-column>
        </el-table>
        
        <div class="step-footer">
           <el-pagination
            v-model:current-page="currentPage"
            v-model:page-size="pageSize"
            layout="total, prev, pager, next"
            :total="total"
            @current-change="loadBackups"
          />
           <el-button type="primary" :disabled="!selectedBackupId" @click="nextStep">下一步</el-button>
        </div>
      </div>

      <!-- Step 2: Select Type & Map Fields -->
      <div v-show="activeStep === 1">
        <h3>第二步：选择还原内容与字段映射</h3>
        
        <el-form label-width="120px">
           <el-form-item label="还原内容">
             <el-radio-group v-model="restoreType" @change="handleTypeChange">
               <el-radio label="USERS">1. 用户数据 (Users)</el-radio>
               <el-radio label="APPLICATIONS">2. 应用管理数据 (Applications)</el-radio>
               <el-radio label="MAPPINGS">3. 账号映射数据 (Mappings)</el-radio>
             </el-radio-group>
             <div class="type-hint">
                <el-alert v-if="restoreType === 'MAPPINGS'" title="注意：请确保对应的用户和应用已经存在或已还原，否则可能导致还原失败。" type="warning" show-icon :closable="false" />
                <el-alert v-if="restoreType === 'APPLICATIONS'" title="还原应用数据可能会覆盖现有的应用配置。" type="info" show-icon :closable="false" />
             </div>
           </el-form-item>
        </el-form>

        <div v-loading="loadingPreview" class="mapping-container">
           <!-- NEW: App Selection for Mappings -->
           <div v-if="restoreType === 'MAPPINGS' && mappingFiles.length > 0" class="file-selection">
              <h4>选择要还原的应用映射文件</h4>
              <el-table :data="mappingFiles" border style="width: 100%" @selection-change="handleFileSelectionChange">
                 <el-table-column type="selection" width="55" />
                 <el-table-column prop="app_id" label="应用标识 (App ID)" />
                 <el-table-column prop="filename" label="文件名" />
              </el-table>
           </div>

           <h4>字段映射配置</h4>
           <div v-if="csvHeaders.length === 0 && !loadingPreview" class="no-data-hint">
              无法从备份中读取到该类型的CSV文件头，请确认备份文件包含该数据。
           </div>
           <el-table v-else :data="mappingData" border style="width: 100%">
              <el-table-column prop="csv" label="备份文件字段 (CSV Header)" />
              <el-table-column label="数据库字段 (DB Column)">
                 <template #default="scope">
                    <el-select v-model="scope.row.db" placeholder="选择目标字段" clearable filterable>
                       <el-option v-for="col in dbColumns" :key="col" :label="col" :value="col" />
                    </el-select>
                 </template>
              </el-table-column>
           </el-table>
        </div>

        <div class="step-footer">
           <el-button @click="activeStep = 0">上一步</el-button>
           <el-button type="primary" :disabled="csvHeaders.length === 0" @click="openConfirmDialog">开始还原</el-button>
        </div>
      </div>

    </el-card>

    <!-- Confirmation Dialog -->
    <el-dialog v-model="confirmVisible" title="安全验证与确认" width="500px">
       <el-alert
         title="操作不可逆！"
         description="确认还原操作？这将修改数据库中的数据。请再次确认已做好备份。"
         type="error"
         show-icon
         :closable="false"
         style="margin-bottom: 20px"
       />
       
       <el-form :model="confirmForm" label-width="100px" ref="formRef">
          <el-form-item label="登录密码">
             <!-- Fake fields to trick browser -->
             <input style="display:none" type="text" name="fakeusernameremembered"/>
             <input style="display:none" type="password" name="fakepasswordremembered"/>

             <el-input 
                v-model="confirmForm.password" 
                type="password" 
                show-password 
                placeholder="请输入当前登录密码" 
                autocomplete="new-password"
                name="new-password-field-random"
             />
          </el-form-item>
          
          <el-form-item label="验证码">
             <div class="captcha-row">
               <el-input v-model="confirmForm.captcha_code" placeholder="图形验证码" style="width: 150px" />
               <div class="captcha-img" @click="refreshCaptcha" v-if="captchaImage">
                  <img :src="captchaImage" alt="captcha" />
               </div>
             </div>
          </el-form-item>

          <el-form-item label="短信验证码">
             <div class="captcha-row">
                <el-input v-model="confirmForm.sms_code" placeholder="短信验证码" style="width: 150px" />
                <el-button 
                    type="primary" 
                    :disabled="smsCooldown > 0 || !confirmForm.captcha_code" 
                    @click="sendSms"
                >
                    {{ smsCooldown > 0 ? `${smsCooldown}s 后重发` : '发送短信' }}
                </el-button>
             </div>
          </el-form-item>
       </el-form>

       <template #footer>
          <el-button @click="confirmVisible = false">取消</el-button>
          <el-button type="danger" :loading="restoring" @click="handleRestore">确认还原</el-button>
       </template>
    </el-dialog>

  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted, computed, watch, onUnmounted } from 'vue'
import { ElMessage, UploadRequestOptions } from 'element-plus'
import { 
  getBackups, 
  previewRestore,
  restoreBackup,
  sendRestoreSms,
  uploadBackup,
  type BackupRecord,
  type MappingFileInfo
} from '../../../api/backup'
import api from '../../../utils/request'

// --- State ---
const activeStep = ref(0)
const backupList = ref<BackupRecord[]>([])
const loadingList = ref(false)
const total = ref(0)
const currentPage = ref(1)
const pageSize = ref(10)
const selectedBackupId = ref<number | null>(null)
const uploading = ref(false)

const restoreType = ref('USERS') // Default to step 1
const loadingPreview = ref(false)
const csvHeaders = ref<string[]>([])
const dbColumns = ref<string[]>([])
const mappingData = ref<{csv: string, db: string}[]>([])
const mappingFiles = ref<MappingFileInfo[]>([])
const selectedFiles = ref<string[]>([])

const confirmVisible = ref(false)
const restoring = ref(false)
const confirmForm = reactive({
  password: '',
  captcha_id: '',
  captcha_code: '',
  sms_code: ''
})
const captchaImage = ref('')
const smsCooldown = ref(0)
let timer: any = null

// --- Methods: Step 1 ---
const loadBackups = async () => {
  loadingList.value = true
  try {
    const res = await getBackups({
       skip: (currentPage.value - 1) * pageSize.value,
       limit: pageSize.value,
       sort_order: 'desc'
    })
    if (res.data && Array.isArray(res.data.items)) {
       backupList.value = res.data.items
       total.value = res.data.total
    } else {
       backupList.value = []
    }
  } catch (e) {
    ElMessage.error('加载备份列表失败')
  } finally {
    loadingList.value = false
  }
}

const handleUpload = async (options: UploadRequestOptions) => {
    uploading.value = true
    try {
        await uploadBackup(options.file)
        ElMessage.success('上传成功')
        // Refresh list
        currentPage.value = 1
        loadBackups()
    } catch (e) {
        ElMessage.error('上传失败')
    } finally {
        uploading.value = false
    }
}

const handleBackupSelect = (row: BackupRecord | undefined) => {
    if (row) selectedBackupId.value = row.id
}

const nextStep = () => {
    if (!selectedBackupId.value) return
    activeStep.value = 1
    loadPreview()
}

// --- Methods: Step 2 ---
const loadPreview = async () => {
   if (!selectedBackupId.value) return
   loadingPreview.value = true
   mappingFiles.value = []
   selectedFiles.value = []
   try {
      const res = await previewRestore(selectedBackupId.value, restoreType.value)
      csvHeaders.value = res.data.csv_headers
      dbColumns.value = res.data.db_columns
      
      if (res.data.mapping_files) {
          mappingFiles.value = res.data.mapping_files
      }
      
      // Auto mapping
      mappingData.value = csvHeaders.value.map(header => {
         // Try exact match
         let match = dbColumns.value.find(col => col === header)
         return {
            csv: header,
            db: match || ''
         }
      })
   } catch (e) {
      ElMessage.error('读取备份文件失败或格式错误')
      csvHeaders.value = []
   } finally {
      loadingPreview.value = false
   }
}

const handleTypeChange = () => {
    loadPreview()
}

const handleFileSelectionChange = (selection: MappingFileInfo[]) => {
    selectedFiles.value = selection.map(item => item.filename)
}

// --- Methods: Confirmation ---
const refreshCaptcha = async () => {
  try {
    const res = await api.get('/utils/captcha')
    confirmForm.captcha_id = res.data.captcha_id
    captchaImage.value = res.data.image
    confirmForm.captcha_code = ''
  } catch (e) {
    ElMessage.error('获取验证码失败')
  }
}

const openConfirmDialog = () => {
   if (restoreType.value === 'MAPPINGS' && mappingFiles.value.length > 0 && selectedFiles.value.length === 0) {
       ElMessage.warning('请至少选择一个要还原的应用映射文件')
       return
   }
   confirmForm.password = ''
   confirmForm.sms_code = ''
   refreshCaptcha()
   confirmVisible.value = true
}

const sendSms = async () => {
    if (!confirmForm.captcha_code) {
        ElMessage.warning('请先输入图形验证码')
        return
    }
    
    try {
        await sendRestoreSms({
            captcha_id: confirmForm.captcha_id,
            captcha_code: confirmForm.captcha_code
        })
        ElMessage.success('短信验证码已发送')
        
        // Start Cooldown
        smsCooldown.value = 60
        timer = setInterval(() => {
            smsCooldown.value--
            if (smsCooldown.value <= 0) {
                clearInterval(timer)
            }
        }, 1000)
        
    } catch (e: any) {
        // Refresh captcha on failure as it's one-time use
        refreshCaptcha() 
        const msg = e.response?.data?.detail || '发送短信失败'
        ElMessage.error(msg)
    }
}

const handleRestore = async () => {
    if (!confirmForm.password || !confirmForm.sms_code) {
        ElMessage.warning('请输入密码和短信验证码')
        return
    }
    
    // Build mapping dict
    const field_mapping: Record<string, string> = {}
    mappingData.value.forEach(item => {
        if (item.db) {
            field_mapping[item.csv] = item.db
        }
    })
    
    restoring.value = true
    try {
        const res = await restoreBackup(selectedBackupId.value!, {
            restore_type: restoreType.value as any,
            field_mapping,
            password: confirmForm.password,
            sms_code: confirmForm.sms_code,
            selected_files: selectedFiles.value.length > 0 ? selectedFiles.value : undefined
        })
        
        ElMessage.success(res.data.message || '还原成功')
        confirmVisible.value = false
        activeStep.value = 0
    } catch (e: any) {
        const msg = e.response?.data?.detail || '还原失败'
        ElMessage.error(msg)
    } finally {
        restoring.value = false
    }
}

// --- Utils ---
const formatSize = (bytes: number) => {
  if (!bytes && bytes !== 0) return '未知'
  if (bytes === 0) return '0 B'
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

const formatDate = (dateStr: string) => {
    if (!dateStr) return '-'
    return new Date(dateStr).toLocaleString()
}

onMounted(() => {
   loadBackups()
})

onUnmounted(() => {
    if (timer) clearInterval(timer)
})
</script>

<style scoped>
.app-container {
  padding: 20px;
}
.card-header {
  display: flex;
  align-items: center;
}
.step-footer {
    margin-top: 20px;
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    align-items: center;
}
.type-hint {
    margin-top: 10px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.mapping-container {
    margin-top: 30px;
}
.file-selection {
    margin-bottom: 20px;
}
.no-data-hint {
    color: #909399;
    padding: 20px;
    text-align: center;
    border: 1px dashed #dcdfe6;
}
.captcha-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.captcha-img {
  cursor: pointer;
  height: 32px;
  display: flex;
  align-items: center;
}
.captcha-img img {
    height: 100%;
}
</style>
