<template>
    <Breadcrumb pageTitle="爬虫列表"></Breadcrumb>
    <div class="space"></div>
    <el-card v-loading="loading">
        <el-header>
            <div class="action-bar-container">
                <el-space class="action-bar-item-container action-bar-action-left">
                    <el-button-group class="ml-4">
                        <el-button type="primary" :icon="Refresh" @click="resetFilterAndRefreshTableList">刷新</el-button>
                        <el-button type="primary" :icon="Box" @click="clickClaimCodes" v-if="showRenLingButton">认领</el-button>
                    </el-button-group>
                </el-space>
                <el-space class="action-bar-item-container action-bar-action-right">
                    <div class="action-bar-item" v-if="showModifyUserFilter">
                        <span class="action-bar-name">维护人：</span>
                        <el-select v-model="filters.modifyuser" style="width: 110px" @change="onModifyUserSelectChange" :disabled="modifyUserSelectDisabled">
                            <el-option
                                v-for="item in filterConfig.modifyUserList"
                                :key="item.value"
                                :label="item.label"
                                :value="item.value"
                            />
                        </el-select>
                    </div>
                    <div class="action-bar-item">
                        <span class="action-bar-name">爬虫状态：</span>
                        <el-select v-model="filters.state" placeholder="爬虫状态" style="width: 110px" @change="onStateSelectChange">
                            <el-option
                                v-for="item in filterConfig.stateOptions"
                                :key="item.value"
                                :label="item.label"
                                :value="item.value"
                            />
                        </el-select>
                    </div>
                    <div class="action-bar-item">
                        <span class="action-bar-name">认领状态：</span>
                        <el-select v-model="filters.claimtype" placeholder="认领状态" style="width: 110px" @change="onClaimSelectChange">
                            <el-option
                                v-for="item in filterConfig.claimOptions"
                                :key="item.value"
                                :label="item.label"
                                :value="item.value"
                                :disabled="item.disabled"
                            />
                        </el-select>
                    </div>
                    <div class="action-bar-item">
                        <el-input v-model="filters.search" placeholder="按照站点、爬虫代码搜索" @keydown.enter="onInputSearch" />
                    </div>
                    <div class="action-bar-item">
                        <el-button type="primary" :icon="Search" @click="onInputSearch">搜索</el-button>
                    </div>
                </el-space>
            </div>
        </el-header>
        <el-main>
            <el-table ref="spiderTable" :data="listState.list" stripe :row-style="getRowStyle" v-loading="listState.loading">
                <el-table-column prop="site" label="网站" align="center" show-overflow-tooltip></el-table-column>
                <el-table-column prop="channel" label="栏目" align="center" show-overflow-tooltip></el-table-column>
                <el-table-column prop="code" label="代码" align="center" show-overflow-tooltip></el-table-column>
                <el-table-column prop="stateText" label="爬虫状态" width="80" align="center" show-overflow-tooltip></el-table-column>
                <el-table-column prop="claimText" label="认领状态" width="100" align="center" show-overflow-tooltip></el-table-column>
                <el-table-column prop="href" label="栏目地址" show-overflow-tooltip></el-table-column>
                <el-table-column prop="modifyUserText" label="维护人" width="120" align="center" show-overflow-tooltip></el-table-column>
                <el-table-column label="操作" width="160" align="center">
                    <template #default="scope">
                  <!-- <el-tooltip content="标注" placement="top">
                            <el-button size="small" :class="{ active: scope.row._action_clicked_mark }" @click="tableEvents.handleDataTag(scope.row)">
                                <el-icon><Link /></el-icon>
                            </el-button>
                        </el-tooltip>-->
                        <el-tooltip content="编辑" placement="top">
                            <el-button size="small" :class="{ active: scope.row._action_clicked_edit }" @click="tableEvents.handleEdit(scope.$index, scope.row)">
                                <el-icon><Edit /></el-icon>
                            </el-button>
                        </el-tooltip>
                        <el-tooltip content="调试" placement="top">
                            <el-button size="small" :class="{ active: scope.row._action_clicked_debug }" @click="tableEvents.handleDebug(scope.$index, scope.row)">
                                <el-icon><SetUp /></el-icon>
                            </el-button>
                        </el-tooltip>
                        <el-tooltip content="验证" placement="top">
                            <el-button size="small" :class="{ active: scope.row._action_clicked_verify }" @click="tableEvents.handleVerify(scope.$index, scope.row)">
                                <el-icon><Aim /></el-icon>
                            </el-button>
                        </el-tooltip>
                    </template>
                </el-table-column>
                <el-table-column label="功能" width="120" align="center">
                    <template #default="scope">
                        <el-tooltip content="提交" placement="top" v-if="showListDevelopeButton">
                            <!-- 爬虫状态是待完成，才可点击提交 -->
                            <el-button size="small" :disabled="tableActionDisabled.submitDisabled(scope.row)" :class="{ active: scope.row._action_clicked_submit }" @click="tableEvents.handleSubmit(scope.$index, scope.row)">
                                <el-icon><Promotion /></el-icon>
                            </el-button>
                        </el-tooltip>
                        <el-tooltip content="退回" placement="top" v-if="showListRollbackButton">
                            <!-- 爬虫状态是待完成，才可点击退回 -->
                            <el-button size="small" :disabled="scope.row.state !== 0" :class="{ active: scope.row._action_clicked_rollback }" @click="tableEvents.handleRollback(scope.$index, scope.row)">
                                <el-icon><DArrowLeft /></el-icon>
                            </el-button>
                        </el-tooltip>
                    </template>
                </el-table-column>
            </el-table>
            <div class="space"></div>
            <div class="pagination-container">
                <el-pagination align="right" @size-change="handleSizeChange" @current-change="handleCurrentChange"
                    :current-page="listState.pageNum" :page-sizes="[10, 20, 30, 40]" :page-size="listState.pageSize"
                    layout="total, sizes, prev, pager, next, jumper" :total="listState.total">
                </el-pagination>
            </div>
        </el-main>
    </el-card>
    <EditSpider ref="editSpiderDialog"
        @custom-event="dialogEvents.editSpiderConfigSaveEvent"
        @data-tag="editDialogMarkClick($event)"
        @form-change="onEditFormChange"
    />
    <RunSpiderDialog ref="runSpiderDialog" />
    <VerifySpider ref="verifySpiderDialog" />
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted, reactive, watch } from 'vue'
import { useRouter } from 'vue-router';
import { useStore } from 'vuex';
import { ElMessage, ElMessageBox } from 'element-plus'
import { BrowserOpenURL, EventsOn } from "../../wailsjs/runtime"
import { VerifySpiderConfig, ServerActionUpdateCodeState, ServerActionCurrentOpenTab } from "../../wailsjs/go/main/App"
import Breadcrumb from "../components/Breadcrumb.vue"
import EditSpider from "../components/spider/EditSpider.vue"
import RunSpiderDialog from "../components/spider/RunSpiderDialog.vue"
import VerifySpider from "../components/spider/VerifySpider.vue"
import { useCodeListFiltersWithRole } from '../composables/filter-options'
import { USER_ROLE_ADMIN, USER_ROLE_DEVELOPER, USER_ROLE_REVIEWER } from '../data/user'
import { Refresh, Search, Box } from '@element-plus/icons-vue'

const router = useRouter();
const store = useStore();
const spiderTable = ref(null)

const { stateOptions, claimOptions } = useCodeListFiltersWithRole()

const loading = ref(false)

const filterConfig = reactive({
    // 爬虫状态备选项
    stateOptions: stateOptions,
    // 认领状态备选项
    claimOptions: claimOptions,
    // 维护人备选项
    modifyUserList: [
        {
            label: '全部',
            value: '-1',
        }
    ]
})

// 选择器数据
const filters = reactive({
    // 搜索
    search: '',
    // 爬虫状态
    state: -1,
    // 维护人
    modifyuser: '-1',
    // 认领状态
    claimtype: -1,
})
// 选择器数据(用来重置)
const defaultFilters = {
    search: '',
    state: -1,
    modifyuser: '-1',
    claimtype: -1,
}

// 列表数据
const listState = reactive({
    loaded: false,
    loading: false,
    pageNum: 1, // 页码
    pageSize: 10, // 每页多少条
    total: 0, // 返回的总数据条数
    list: [ // 数据列表
        // {
        //     code: '爬虫代码', 
        //     site: '网站',
        //     channel: '栏目',
        //     href: '栏目地址',
        //     modifyuser: '维护人',
        //     _id: 'asfasf',
        // },
    ],
})
// 列表默认数据(用来重置)
const defaultListState = {
    loaded: false,
    loading: false,
    pageNum: 1,
    pageSize: 10,
    total: 0,
    list: [],
}

// 当前编辑的row的数据
const currentEditRow = ref({})
// 上一个点击的row的数据
const prevClickedRow = ref({})

// 用户身份标识
const userRole = computed(() => store.getters.userRole)
// 是否展示维护人模块(管理员和审核员展示)
const showModifyUserFilter = computed(() => [USER_ROLE_ADMIN, USER_ROLE_REVIEWER].includes(userRole.value))
// 是否展示认领按钮(仅开发人员展示)
const showRenLingButton = computed(() => [USER_ROLE_DEVELOPER].includes(userRole.value))
// 是否展示提交按钮(仅开发人员展示)
const showListDevelopeButton = computed(() => [USER_ROLE_DEVELOPER].includes(userRole.value))
// 是否展示退回按钮(仅开发人员展示)
const showListRollbackButton = computed(() => [USER_ROLE_DEVELOPER].includes(userRole.value))

// 实现待认领不能和维护人同时筛选
// 是否禁用维护人模块(待认领筛选下，禁用维护人筛选模块)
const modifyUserSelectDisabled = computed(() => filters.claimtype === 0)
// 是否禁用待认领筛选(维护人不为全部，则禁用待认领的选中)
const stopWatch = watch(() => filters.modifyuser, (n) => {
    const target = filterConfig.claimOptions.find(i => i.value === 0)
    if (target) {
        if (n === defaultFilters.modifyuser) {
            // 解除禁用待认领
            target.disabled = false
        } else {
            // 禁用待认领
            target.disabled = true
        }
    } else {
        stopWatch()
    }
})

const editSpiderDialog = ref(null)
const runSpiderDialog = ref(null)
const verifySpiderDialog = ref(null)

// 取消prevClicked的高亮
const cancelOtherHighlight = () => {
    for (const key in prevClickedRow.value) {
        if (key.includes('_action_clicked')) {
            prevClickedRow.value[key] = false
        }
    }
}
// 页面按钮点击高亮
const onlyClickHighlight = (row, key) => {
    cancelOtherHighlight()
    row[key] = true
    prevClickedRow.value = row
}

const getRowStyle = ({ row }) => {
    return row.selected ? { backgroundColor: '#F7F7F7' } : {};
};

// 计算爬虫状态
const calcStateText = (state) => {
    const target = filterConfig.stateOptions.find(r => r.value === state)
    if (target) {
        return target.label
    } else {
        return ''
    }
}
// 计算认领状态
const calcClaimText = (state) => {
    const target = filterConfig.claimOptions.find(r => r.value === state)
    if (target) {
        return target.label
    } else {
        return ''
    }
}
const calcModifyUserText = (state) => {
    // 未认领状态。维护人返回无
    if (state.claimtype === 0) {
        return '无'
    } else {
        return state.modifyuser
    }
}
// 获取列表数据
async function getTableList() {
    listState.loading = true
    try {
        const r = await store.dispatch('rulesList/getCodeList', {
            modifyuser: filters.modifyuser, // 维护人
            state: filters.state, // 爬虫状态
            search: filters.search, // 搜索内容
            claimtype: filters.claimtype,
            pageType: 'codelist',
            pageSize: listState.pageSize,
            pageNum: listState.pageNum
        });
        const { data, err, msg } = r
        if (data) {
            listState.total = data.total || 0
            if (Array.isArray(data.list)) {
                const sList = data.list.map(t => {
                    return {
                        ...t,
                        stateText: calcStateText(t.state),
                        claimText: calcClaimText(t.claimtype),
                        modifyUserText: calcModifyUserText(t),
                        // 操作按钮是否点击过
                        _action_clicked_mark: false,
                        _action_clicked_edit: false,
                        _action_clicked_debug: false,
                        _action_clicked_verify: false,
                        _action_clicked_submit: false,
                        _action_clicked_rollback: false,
                    }
                })

                listState.list = sList || []
            }
        }
    } catch (error) {
        listState.loaded = true
    } finally {
        listState.loading = false
    }
}

// 重置列表数据
const resetListState = () => {
    Object.assign(listState, defaultListState)
}
// 重置选择器数据
const resetFilterState = () => {
    Object.assign(filters, defaultFilters)
}

// 刷新列表(不重置选择器)
function refreshTableList() {
    resetListState()
    getTableList()
}
// 刷新列表(并重置选择器)
function resetFilterAndRefreshTableList() {
    resetFilterState()
    refreshTableList()
}

// 认领按钮事件
const userClaimCodes = async () => {
    try {
        const r = await store.dispatch('rulesList/userClaimCodes')
        const { msg, err } = r
        if (err === 1) {
            ElMessage({
                message: msg || '认领成功',
                type: 'success',
                duration: 3000,
            })
            resetFilterAndRefreshTableList()
        } else {
            ElMessage({
                message: msg || '认领失败',
                type: 'error',
                duration: 3000,
            })
        }
    } catch (error) {
        ElMessage({
            message: '认领失败',
            type: 'error',
            duration: 3000,
        })
    }
}
const clickClaimCodes = () => {
    ElMessageBox.confirm('确定要认领爬虫？', '提示',
        {
            customClass: 'j-confirm-message-box',
            type: 'warning',
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            showCancelButton: false,
        }
    ).then(() => {
        userClaimCodes()
    })
}

getTableList()

const handleSizeChange = (val) => {
    listState.pageSize = val;
    listState.pageNum = 1;
    getTableList()
};

const handleCurrentChange = (val) => {
    listState.pageNum = val;
    getTableList()
};

// 获取维护人劣列表
const getModifyUserList = async () => {
    const r = await store.dispatch('rulesList/getModifyUserList')
    const { data, err, msg } = r
    if (data) {
        if (Array.isArray(data.list)) {
            const arr = filterConfig.modifyUserList
            const reqArr = data.list.map(r => {
                return {
                    label: r.s_name,
                    value: r.s_name,
                }
            })
            filterConfig.modifyUserList = arr.concat(reqArr)
        }
    }
}
getModifyUserList()

const onModifyUserSelectChange = () => {
    refreshTableList()
}
const onStateSelectChange = () => {
    refreshTableList()
}
const onInputSearch = () => {
    refreshTableList()
}
const onClaimSelectChange = () => {
    refreshTableList()
}

// 保存完成后(不刷新优化)，同步更新表单内的数据
const refreshRowData = (code, payload) => {
    const target = listState.list.find(item => item.code === code)
    if (target) {
        if (target.cssmark) {
            Object.assign(target.cssmark, payload)
        } else {
            target.cssmark = payload            
        }
    }
}
// 更新编辑弹窗数据
const refreshAndAsyncEditDialog = (key, value) => {
    editSpiderDialog.value.refreshPageData(key, value)
}

// 打开编辑弹窗(如果传数据了，则恢复数据)
const openEditDialog = (row) => {
    editSpiderDialog.value.dialogVisible = true
    if (row) {
        editSpiderDialog.value.setPageData({
            ...row,
            ...row.cssmark,
        })
    }
}


const dialogEvents = {
    editSpiderConfigSaveEvent: async function (data) {
        // 整理数据结构
        // [{ query: {code: 'code'}, set: {} }, {query:{},set:{}}]
        const rowData = data._originData
        const payload = data.value
        const code = rowData.code
        const updateRule = [
            {
                query: { code: code },
                set: {
                    cssmark: payload,
                }
            }
        ]
        const params = {
            stype: 'save',
            update: updateRule
        }
        console.log("change data:", data, params)
        try {
            const r = await store.dispatch('rulesList/editCodeItem', params)
            const { msg, err } = r
            if (err === 1) {
                refreshRowData(code, payload)
                ElMessage({
                    message: msg || '保存成功',
                    type: 'success',
                    duration: 3000,
                })
                // getTableList()
            } else {
                ElMessage({
                    message: msg || '保存失败',
                    type: 'error',
                    duration: 3000,
                })
            }
        } catch (error) {
            ElMessage({
                message: '保存失败',
                type: 'error',
                duration: 3000,
            })
        }
    },
}

const getMarkWithRow = row => {
    const baseInfo = {
        code: row.code,
        site: row.site,
        channel: row.channel,
        href: row.href,
        modifyuser: row.modifyuser,
    }

    if (row.cssmark) {
        return {
            ...row.cssmark,
            ...baseInfo,
        }
    } else {
        return baseInfo
    }
}

// 根据编辑弹窗的内容，获取cssMark
const getMarkWithEditDialogInfo = info => {
    const { value, _originData } = info
    const baseInfo = {
        code: _originData.code,
        site: _originData.site,
        channel: _originData.channel,
        href: _originData.href,
        modifyuser: _originData.modifyuser,
    }
    return {
        ...value,
        ...baseInfo,
    }
}

const getLuaParams = row => {
    const baseInfo = {
        code: row.code,
        site: row.site,
        channel: row.channel,
        modifyuser: row.modifyuser,
        claimtime: row.claimtime,
        recovertime: row.recovertime,
        priority: row.priority,
        spiderimportant: row.spiderimportant,
        modifytime: row.modifytime,
    }
    return baseInfo
}

const editDialogMarkClick = (row) => {
    // 自定义关闭时间
    ElMessage({
        message: `${row.site} ${row.channel} ${row.href}`,
        showClose: true,
        duration: 3000,
    });
    BrowserOpenURL(row.href)
}

// table的按钮事件集合
const tableEvents = {
    handleDataTag(row) {
        onlyClickHighlight(row, '_action_clicked_mark')
        // 自定义关闭时间
        editDialogMarkClick(row)
    },
    handleEdit: (index, row) => {
        currentEditRow.value = row
        onlyClickHighlight(row, '_action_clicked_edit')
        prevClickedRow.value = row
        ElMessage({
            message: `${row.site} ${row.channel} ${row.href}`,
            showClose: true,
            duration: 3000,
        });
        const mark = getMarkWithRow(row)
        ServerActionCurrentOpenTab(mark)
        openEditDialog(row)
    },
    handleDebug(index, row) {
        onlyClickHighlight(row, '_action_clicked_debug')
        runSpiderDialog.value.dialogVisible = true
        runSpiderDialog.value.setPageData(row)
        // router.push({
        //     path: '/run'
        // });
    },
    handleVerify(index, row) {
        onlyClickHighlight(row, '_action_clicked_verify')
        loading.value = true
        if (!row.cssmark) {
            return ElMessage({
                message: '没有找到标注信息',
                type: 'error',
                duration: 3000,
            })
        }
        const mark = getMarkWithRow(row)
        VerifySpiderConfig(mark).then(r => {
            if (r.err === 1 && r.ret) {
                verifySpiderDialog.value.dialogVisible = true
                verifySpiderDialog.value.formData = r.ret
            } else {
                return ElMessage({
                    message: r.msg || '验证异常',
                    type: 'error',
                    duration: 3000,
                })
            }
        }).finally(() => {
            loading.value = false
        })
    },
    handleSubmit(index, row) {
        onlyClickHighlight(row, '_action_clicked_submit')
        const lua = getLuaParams(row)
        lua.state = 1
        ServerActionUpdateCodeState({ lua: lua }).then(r => {
            if (r.err === 1) {
                ElMessage({
                    message: '提交成功',
                    type: 'success',
                    duration: 3000,
                })
                getTableList()
            } else {
                return ElMessage({
                    message: r.msg || '提交失败',
                    type: 'error',
                    duration: 3000,
                })
            }
        })
    },
    handleRollback(_, row) {
        onlyClickHighlight(row, '_action_clicked_rollback')
        // ElMessageBox.alert('确定退回？', '提示', {
        //     customClass: 'j-confirm-message-box',
        //     confirmButtonText: '确定',
        //     callback: (action) => {
        //         if (action === 'confirm') {
        //             
        //         }
        //     },
        // })
        ElMessageBox.confirm('确定退回？', '提示',
            {
                customClass: 'j-confirm-message-box',
                type: 'warning',
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                showCancelButton: false,
            }
        ).then(() => {
            this.confirmRollback(row)
        })
    },
    confirmRollback(row) {
        const lua = getLuaParams(row)
        lua.state = 12
        ServerActionUpdateCodeState({ lua: lua }).then(r => {
            if (r.err === 1) {
                ElMessage({
                    message: '退回成功',
                    type: 'success',
                    duration: 3000,
                })
                getTableList()
            } else {
                return ElMessage({
                    message: r.msg || '退回失败',
                    type: 'error',
                    duration: 3000,
                })
            }
        })
    },
}

// 表格按钮是否可用
const tableActionDisabled = {
    // 此按钮是开发者才会展示
    submitDisabled(row) {
        // 开发者-爬虫状态是待完成，才可点击提交
        const waitingComplete = row.state === 0
        // 开发者-未通过的爬虫可点击提交
        const notPass = row.state === 2
        const canSubmit = waitingComplete || notPass
        return !canSubmit
    }
}


const onEditFormChange = (info) => {
    const mark = getMarkWithEditDialogInfo(info)
    ServerActionCurrentOpenTab(mark)
}

//Wails事件绑定
EventsOn("spiderConfigChange", data => {
    console.log(data)
    const { key, css, url } = data
    refreshAndAsyncEditDialog(key, css)
    // 当触发修改时候，同步给客服端一份
    if (currentEditRow.value && Object.keys(currentEditRow.value).length <= 0) {
        const mark = getMarkWithRow(currentEditRow.value)
        ServerActionCurrentOpenTab(mark)
    }
    // 判断标注url和编辑url是否相同
    // const editUrl = currentEditRow.href
    // if (url === editUrl) {
    //     refreshAndAsyncEditDialog(key, css[key])
    // } else {
    //     ElMessage({
    //         message: `标注url和编辑url不匹配，此次更新取消。当前标注url: ${url}，当前编辑url: ${editUrl}`,
    //         type: 'warn',
    //         duration: 4000,
    //     })
    // }
})
</script>

<style lang="scss" scoped>
::v-deep {
    .el-button {
        &.active {
            background-color: var(--el-button-hover-bg-color);
            border-color: var(--el-button-hover-border-color);
            color: var(--el-button-hover-text-color);
            outline: none;
        }
    }
}

.pagination-container {
    display: flex;
    align-items: center;
    justify-content: flex-end;
}
.action-bar-container {
    display: flex;
    justify-content: space-between;
}
.action-bar-item-container {
    
}
.action-bar-item {
    display: flex;
    align-items: center;
}
.action-bar-name {
    font-size: 14px;
    white-space: nowrap;
}
</style>