<template>
    <div class="table-box dbms-page">
        <div class="dbms-workbench">
            <DbmsToolbar :has-selected-connection="Boolean(selectedConnection)" @command="handleToolbarCommand" />

            <div class="dbms-main" :class="{ 'is-tree-collapsed': treeCollapsed }">
                <aside class="dbms-tree-panel">
                    <DbmsConnectionTree
                        :connections="connections"
                        :loading="connectionLoading"
                        :collapsed="treeCollapsed"
                        @toggle="treeCollapsed = !treeCollapsed"
                        @refresh="loadConnections"
                        @select-connection="handleSelectConnection"
                        @select-section="handleSelectSection"
                    />
                </aside>

                <main class="dbms-workspace-panel">
                    <DbmsWorkspace
                        :active-section="activeSection"
                        :selected-connection="selectedConnection"
                        :tables="tables"
                        :files="files"
                        :tasks="tasks"
                        :task-query="taskQuery"
                        :file-query="fileQuery"
                        :table-loading="tableLoading"
                        :task-loading="taskLoading"
                        :file-loading="fileLoading"
                        :task-total="taskTotal"
                        :task-page-num="taskPage.pageNum"
                        :task-page-size="taskPage.pageSize"
                        :file-total="fileTotal"
                        :file-page-num="filePage.pageNum"
                        :file-page-size="filePage.pageSize"
                        @edit-connection="row => openConnectionDialog('edit', row)"
                        @load-tables="loadTables"
                        @backup="handleCreateBackup"
                        @restore="handleCreateRestore"
                        @refresh-tasks="loadTasks"
                        @refresh-files="loadFiles"
                        @search-tasks="handleSearchTasks"
                        @search-files="handleSearchFiles"
                        @check-task="handleCheckTask"
                        @delete-task="handleDeleteTask"
                        @delete-file="handleDeleteFile"
                        @task-page-change="handleTaskPageChange"
                        @task-size-change="handleTaskSizeChange"
                        @file-page-change="handleFilePageChange"
                        @file-size-change="handleFileSizeChange"
                    />
                </main>
            </div>
        </div>

        <DbmsConnectionTypeDialog ref="connectionTypeDialogRef" @next="handleSelectConnectionType" />
        <DbmsConnectionDialog ref="connectionDialogRef" @save="handleSaveConnection" @test="handleTestConnectionPayload" />
    </div>
</template>

<script setup lang="ts">
import { reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { Dbms } from '@/api/system/dbms/interface'
import {
    addDbmsConnection,
    createDbmsBackupTask,
    createDbmsRestoreTask,
    deleteDbmsBackupFile,
    deleteDbmsConnection,
    deleteDbmsTask,
    getDbmsBackupFileList,
    getDbmsBackupTaskList,
    getDbmsBackupTaskStatus,
    getDbmsConnectionList,
    getDbmsRestoreTaskStatus,
    getDbmsTableList,
    testDbmsConnection,
    updateDbmsConnection
} from '@/api/system/dbms'
import DbmsConnectionDialog from './components/DbmsConnectionDialog.vue'
import DbmsConnectionTypeDialog from './components/DbmsConnectionTypeDialog.vue'
import DbmsConnectionTree from './components/DbmsConnectionTree.vue'
import DbmsToolbar from './components/DbmsToolbar.vue'
import DbmsWorkspace from './components/DbmsWorkspace.vue'
import type {
    DbmsConnectionQuery,
    DbmsFileQuery,
    DbmsTaskQuery,
    DbmsToolbarCommand,
    DbmsWorkspaceSection
} from './components/types'
import {
    buildBackupPayload,
    buildDeleteBackupFilePayload,
    buildDeleteTaskPayload,
    buildFileListParams,
    buildRestorePayload,
    buildTaskListParams
} from './utils/taskPayload'
import { DELETE_CONFIRM_TEXT, isTerminalTaskStatus } from './utils/normalize'

defineOptions({
    name: 'DbmsView'
})

type ConnectionDialogExpose = {
    open: (mode: 'add' | 'edit', record?: Dbms.ConnectionRecord, dbType?: Dbms.DbType) => void
    close: () => void
}

type ConnectionTypeDialogExpose = {
    open: () => void
    close: () => void
}

const connectionTypeDialogRef = ref<ConnectionTypeDialogExpose>()
const connectionDialogRef = ref<ConnectionDialogExpose>()
const connections = ref<Dbms.ConnectionRecord[]>([])
const selectedConnection = ref<Dbms.ConnectionRecord | null>(null)
const tables = ref<Dbms.TableRecord[]>([])
const tasks = ref<Dbms.TaskRecord[]>([])
const files = ref<Dbms.BackupFileRecord[]>([])
const activeSection = ref<DbmsWorkspaceSection>('overview')
const treeCollapsed = ref(false)

const connectionLoading = ref(false)
const tableLoading = ref(false)
const taskLoading = ref(false)
const fileLoading = ref(false)
const connectionTotal = ref(0)
const taskTotal = ref(0)
const fileTotal = ref(0)

const connectionPage = reactive({ pageNum: 1, pageSize: 1000 })
const taskPage = reactive({ pageNum: 1, pageSize: 10 })
const filePage = reactive({ pageNum: 1, pageSize: 10 })
const connectionQuery = reactive<DbmsConnectionQuery>({ connectionName: '', schemaName: '' })
const taskQuery = reactive<DbmsTaskQuery>({ taskStatus: '' })
const fileQuery = reactive<DbmsFileQuery>({ taskId: '' })

const loadConnections = async () => {
    connectionLoading.value = true
    try {
        const result = await getDbmsConnectionList({
            pageNum: connectionPage.pageNum,
            pageSize: connectionPage.pageSize,
            connectionName: connectionQuery.connectionName || undefined,
            schemaName: connectionQuery.schemaName || undefined,
            dbType: 'ORACLE'
        })
        connections.value = result.data.records || []
        connectionTotal.value = result.data.total || 0
    } finally {
        connectionLoading.value = false
    }
}

const loadTables = async () => {
    if (!selectedConnection.value) {
        ElMessage.warning('请先选择连接')
        return
    }

    tableLoading.value = true
    try {
        const result = await getDbmsTableList({
            connectionId: selectedConnection.value.id,
            schemaName: selectedConnection.value.schemaName || undefined
        })
        tables.value = result.data || []
    } finally {
        tableLoading.value = false
    }
}

const loadTasks = async () => {
    taskLoading.value = true
    try {
        const result = await getDbmsBackupTaskList(
            buildTaskListParams(taskPage.pageNum, taskPage.pageSize, selectedConnection.value?.id, taskQuery.taskStatus)
        )
        tasks.value = result.data.records || []
        taskTotal.value = result.data.total || 0
    } finally {
        taskLoading.value = false
    }
}

const loadFiles = async () => {
    fileLoading.value = true
    try {
        const result = await getDbmsBackupFileList(
            buildFileListParams(filePage.pageNum, filePage.pageSize, selectedConnection.value?.id, fileQuery.taskId)
        )
        files.value = result.data.records || []
        fileTotal.value = result.data.total || 0
    } finally {
        fileLoading.value = false
    }
}

const openConnectionDialog = (mode: 'add' | 'edit', row?: Dbms.ConnectionRecord) => {
    connectionDialogRef.value?.open(mode, row)
}

const openConnectionTypeDialog = () => {
    connectionTypeDialogRef.value?.open()
}

const handleSelectConnectionType = (dbType: Dbms.DbType) => {
    if (dbType === 'MYSQL') {
        ElMessage.info('MySQL 连接配置暂未接入')
        return
    }

    connectionTypeDialogRef.value?.close()
    connectionDialogRef.value?.open('add', undefined, dbType)
}

const handleSelectSection = async (section: DbmsWorkspaceSection) => {
    activeSection.value = section
    if (section === 'tables') {
        await loadTables()
    }
}

const handleToolbarCommand = async (command: DbmsToolbarCommand) => {
    const commandMap: Partial<Record<DbmsToolbarCommand, () => void | Promise<void>>> = {
        connect: () => openConnectionTypeDialog(),
        newConnection: () => openConnectionTypeDialog(),
        newQuery: () => {
            ElMessage.info('查询编辑器接口暂未接入')
        },
        tables: () => handleSelectSection('tables'),
        views: () => {
            activeSection.value = 'views'
        },
        backup: () => {
            activeSection.value = 'backup'
        }
    }

    await commandMap[command]?.()
}

const handleSearchConnections = (query: DbmsConnectionQuery) => {
    Object.assign(connectionQuery, query)
    connectionPage.pageNum = 1
    loadConnections()
}

const handleSelectConnection = (row: Dbms.ConnectionRecord) => {
    if (selectedConnection.value?.id === row.id) return
    selectedConnection.value = row
    tables.value = []
    activeSection.value = 'overview'
    taskPage.pageNum = 1
    filePage.pageNum = 1
    loadTasks()
    loadFiles()
}

const handleSaveConnection = async (payload: Dbms.ConnectionPayload) => {
    if (payload.id) {
        await updateDbmsConnection(payload)
        ElMessage.success('连接已更新')
    } else {
        await addDbmsConnection(payload)
        ElMessage.success('连接已新增')
    }
    connectionDialogRef.value?.close()
    await loadConnections()
}

const handleTestConnectionPayload = async (payload: Dbms.TestConnectionParams) => {
    const result = await testDbmsConnection(payload)
    ElMessage[result.data.success ? 'success' : 'error'](result.data.message || (result.data.success ? '连接成功' : '连接失败'))
    await loadConnections()
}

const handleTestStoredConnection = (row: Dbms.ConnectionRecord) => {
    handleTestConnectionPayload({ connectionId: row.id })
}

const handleDeleteConnection = async (row: Dbms.ConnectionRecord) => {
    await ElMessageBox.confirm(`确认删除连接“${row.connectionName}”？`, '删除确认', {
        type: 'warning',
        confirmButtonText: DELETE_CONFIRM_TEXT,
        cancelButtonText: '取消'
    })
    await deleteDbmsConnection({ id: row.id })
    if (selectedConnection.value?.id === row.id) {
        selectedConnection.value = null
        tables.value = []
    }
    ElMessage.success('连接已删除')
    await loadConnections()
}

const pollTaskStatus = async (taskId: string, operationType: Dbms.OperationType) => {
    // 异步任务创建后短轮询状态，避免页面停留在 WAITING 无反馈。
    for (let index = 0; index < 8; index += 1) {
        const result =
            operationType === 'RESTORE' ? await getDbmsRestoreTaskStatus(taskId) : await getDbmsBackupTaskStatus(taskId)
        if (isTerminalTaskStatus(result.data.taskStatus)) break
        await new Promise(resolve => window.setTimeout(resolve, 1500))
    }
    await loadTasks()
    await loadFiles()
}

const handleCreateBackup = async ({ form }: { form: import('./utils/taskPayload').DbmsBackupFormModel }) => {
    if (!selectedConnection.value) return
    const result = await createDbmsBackupTask(buildBackupPayload(selectedConnection.value, form))
    ElMessage.success(`备份任务已创建：${result.data.taskNo}`)
    activeSection.value = 'tasks'
    await loadTasks()
    pollTaskStatus(result.data.taskId, 'BACKUP')
}

const handleCreateRestore = async ({ form }: { form: import('./utils/taskPayload').DbmsRestoreFormModel }) => {
    if (!selectedConnection.value) return
    // 覆盖类恢复必须由后端确认文案兜底，前端只负责传递明确确认值。
    const result = await createDbmsRestoreTask(buildRestorePayload(selectedConnection.value, form))
    ElMessage.success(`恢复任务已创建：${result.data.taskNo}`)
    activeSection.value = 'tasks'
    await loadTasks()
    pollTaskStatus(result.data.taskId, 'RESTORE')
}

const handleCheckTask = async (row: Dbms.TaskRecord) => {
    const result =
        row.operationType === 'RESTORE' ? await getDbmsRestoreTaskStatus(row.id) : await getDbmsBackupTaskStatus(row.id)
    ElMessage.info(result.data.resultMessage || '任务状态已刷新')
    await loadTasks()
}

const handleDeleteTask = async (row: Dbms.TaskRecord) => {
    await ElMessageBox.confirm(`确认删除任务“${row.taskNo}”？`, '删除确认', {
        type: 'warning',
        confirmButtonText: DELETE_CONFIRM_TEXT,
        cancelButtonText: '取消'
    })
    await deleteDbmsTask(buildDeleteTaskPayload(row.id))
    ElMessage.success('任务记录已删除')
    await loadTasks()
}

const handleDeleteFile = async (row: Dbms.BackupFileRecord) => {
    await ElMessageBox.confirm(`确认删除备份文件“${row.fileName}”？`, '删除确认', {
        type: 'warning',
        confirmButtonText: DELETE_CONFIRM_TEXT,
        cancelButtonText: '取消'
    })
    await deleteDbmsBackupFile(buildDeleteBackupFilePayload(row.id))
    ElMessage.success('备份文件已删除')
    await loadFiles()
}

const handleSearchTasks = (query: DbmsTaskQuery) => {
    Object.assign(taskQuery, query)
    taskPage.pageNum = 1
    loadTasks()
}

const handleSearchFiles = (query: DbmsFileQuery) => {
    Object.assign(fileQuery, query)
    filePage.pageNum = 1
    loadFiles()
}

const handleTaskPageChange = (page: number) => {
    taskPage.pageNum = page
    loadTasks()
}

const handleTaskSizeChange = (size: number) => {
    taskPage.pageSize = size
    taskPage.pageNum = 1
    loadTasks()
}

const handleFilePageChange = (page: number) => {
    filePage.pageNum = page
    loadFiles()
}

const handleFileSizeChange = (size: number) => {
    filePage.pageSize = size
    filePage.pageNum = 1
    loadFiles()
}

</script>

<style scoped lang="scss">
.dbms-page {
    display: flex;
    flex-direction: column;
    width: 100%;
    height: 100%;
    min-height: 0;
    padding: 0;
    overflow: hidden;
}

.dbms-workbench {
    display: flex;
    flex: 1;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
    background: var(--el-bg-color-page);
    border: 1px solid var(--el-border-color-light);
}

.dbms-main {
    display: grid;
    grid-template-columns: 292px minmax(0, 1fr);
    gap: 8px;
    flex: 1;
    min-height: 0;
    padding: 8px;
    overflow: hidden;
}

.dbms-main.is-tree-collapsed {
    grid-template-columns: 0 minmax(0, 1fr);
}

.dbms-tree-panel {
    position: relative;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
}

.dbms-main.is-tree-collapsed .dbms-tree-panel {
    z-index: 4;
    overflow: visible;
}

.dbms-workspace-panel {
    display: flex;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
}

@media (max-width: 1280px) {
    .dbms-main:not(.is-tree-collapsed) {
        grid-template-columns: 260px minmax(0, 1fr);
    }
}
</style>
