<template>
    <div v-loading="loading">
        <div class="app-status mt-5" v-if="currentDB?.from === 'remote'">
            <el-card>
                <div class="flex w-full flex-col gap-4 md:flex-row">
                    <div class="flex flex-wrap gap-4 ml-3">
                        <el-tag class="float-left" effect="dark" type="success">
                            {{ currentDB?.type === 'mysql' ? 'Mysql' : 'MariaDB' }}
                        </el-tag>
                        <el-tag>{{ $t('app.version') }}: {{ currentDB?.version }}</el-tag>
                    </div>
                </div>
            </el-card>
        </div>
        <LayoutContent>
            <template #app v-if="currentDB?.from === 'local'">
                <AppStatus
                    :app-key="appKey"
                    :app-name="appName"
                    v-model:loading="loading"
                    v-model:mask-show="maskShow"
                    @setting="onSetting()"
                    @is-exist="checkExist"
                    ref="appStatusRef"
                ></AppStatus>
            </template>
            <template #leftToolBar>
                <el-button
                    v-if="currentDB && (currentDB.from !== 'local' || mysqlStatus === 'Running')"
                    v-permission
                    type="primary"
                    @click="onCreateAction()"
                >
                    {{ $t('commons.button.create') }}
                </el-button>
                <el-button v-if="currentDB" @click="onChangeConn()" type="primary" plain>
                    {{ $t('database.databaseConnInfo') }}
                </el-button>
                <el-button v-if="currentDB" @click="openUserDrawer()" type="primary" plain>
                    {{ $t('commons.table.user') }}
                </el-button>
                <el-button
                    v-if="currentDB && (currentDB.from !== 'local' || mysqlStatus === 'Running')"
                    v-permission
                    @click="loadDB"
                    type="primary"
                    plain
                >
                    {{ $t('database.loadFromRemote') }}
                </el-button>
                <el-button @click="goRemoteDB()" type="primary" plain>
                    {{ $t('database.remoteDB') }}
                </el-button>
                <el-button
                    @click="goTerminal()"
                    :disabled="currentDB?.from !== 'local' || !isAdminOrNodeAdmin"
                    type="primary"
                    plain
                >
                    {{ $t('menu.terminal') }}
                </el-button>
                <el-dropdown>
                    <el-button type="primary" plain>
                        {{ $t('database.manage') }}
                        <el-icon class="el-icon--right"><arrow-down /></el-icon>
                    </el-button>
                    <template #dropdown>
                        <el-dropdown-menu>
                            <el-dropdown-item icon="Position" @click="goDashboard('phpMyAdmin')">
                                phpMyAdmin
                            </el-dropdown-item>
                            <el-dropdown-item icon="Position" @click="goDashboard('Adminer')" divided>
                                Adminer
                            </el-dropdown-item>
                        </el-dropdown-menu>
                    </template>
                </el-dropdown>
            </template>
            <template #rightToolBar>
                <el-select v-model="currentDBName" @change="changeDatabase()" class="p-w-200" v-if="currentDB">
                    <template #prefix>{{ $t('commons.table.type') }}</template>
                    <el-option-group :label="$t('commons.table.local')">
                        <div v-for="(item, index) in dbOptionsLocal" :key="index">
                            <el-option v-if="item.from === 'local'" :value="item.database" class="optionClass">
                                <span v-if="item.database.length < 25">{{ item.database }}</span>
                                <el-tooltip v-else :content="item.database" placement="top">
                                    <span>{{ item.database.substring(0, 25) }}...</span>
                                </el-tooltip>
                                <el-tag class="tagClass">
                                    {{ mysqlName(item.type) }}
                                </el-tag>
                            </el-option>
                        </div>
                        <el-button link type="primary" class="jumpAdd" @click="goRouter('app')" icon="Position">
                            {{ $t('database.goInstall') }}
                        </el-button>
                    </el-option-group>
                    <el-option-group :label="$t('database.remote')">
                        <div v-for="(item, index) in dbOptionsRemote" :key="index">
                            <el-option v-if="item.from === 'remote'" :value="item.database" class="optionClass">
                                <span v-if="item.database.length < 25">{{ item.database }}</span>
                                <el-tooltip v-else :content="item.database" placement="top">
                                    <span>{{ item.database.substring(0, 25) }}...</span>
                                </el-tooltip>
                                <el-tag class="tagClass">
                                    {{ mysqlName(item.type) }}
                                </el-tag>
                            </el-option>
                        </div>
                        <el-button link type="primary" class="jumpAdd" @click="goRouter('remote')" icon="Position">
                            {{ $t('database.createRemoteDB') }}
                        </el-button>
                    </el-option-group>
                </el-select>
                <TableSearch @search="search()" v-model:searchName="searchName" />
                <TableRefresh @search="search()" />
            </template>
            <template #main>
                <ComplexTable
                    v-if="currentDB"
                    :pagination-config="paginationConfig"
                    :class="{ mask: maskShow }"
                    @sort-change="search"
                    @search="search"
                    :data="data"
                    :heightDiff="370"
                >
                    <el-table-column :label="$t('commons.table.name')" prop="name" sortable min-width="90">
                        <template #default="{ row }">
                            <Tooltip v-if="!row.isDelete" :islink="false" :text="row.name" />
                            <div v-else>
                                <span v-if="row.name.length < 15">{{ row.name }}</span>
                                <el-tooltip v-else :content="row.name">{{ row.name.substring(0, 10) }}...</el-tooltip>
                                <el-tag round type="info" class="ml-1" size="small">
                                    {{ $t('database.isDelete') }}
                                </el-tag>
                            </div>
                        </template>
                    </el-table-column>
                    <el-table-column :label="$t('database.authorizedUsers')" min-width="130">
                        <template #default="{ row }">
                            <el-button
                                link
                                type="primary"
                                :disabled="row.isDelete"
                                @click="openAuthorizationManagement(row)"
                            >
                                {{ $t('database.authorizedUserCount', [row.authorizedUsers?.length || 0]) }}
                            </el-button>
                        </template>
                    </el-table-column>
                    <el-table-column :label="$t('commons.table.description')" prop="description" show-overflow-tooltip>
                        <template #default="{ row }">
                            <fu-input-rw-switch
                                v-model="row.description"
                                v-permission
                                @enter="onChange(row)"
                                @blur="onChange(row)"
                            />
                        </template>
                    </el-table-column>
                    <el-table-column
                        prop="createdAt"
                        :label="$t('commons.table.date')"
                        :formatter="dateFormat"
                        show-overflow-tooltip
                    />
                    <fu-table-operations
                        :ellipsis="isMobile ? 0 : 10"
                        :min-width="isMobile ? 'auto' : 300"
                        :buttons="buttons"
                        :label="$t('commons.table.operate')"
                        fixed="right"
                        fix
                    />
                </ComplexTable>
                <div v-if="isLoaded && dbOptionsLocal.length === 0 && dbOptionsRemote.length === 0" class="app-warn">
                    <div class="flex flex-col gap-2 items-center justify-center w-full sm:flex-row">
                        <span>{{ $t('app.checkInstalledWarn', [$t('database.noMysql')]) }}</span>
                        <span @click="goRouter('app')" class="flex items-center justify-center gap-0.5">
                            <el-icon><Position /></el-icon>
                            {{ $t('database.goInstall') }}
                        </span>
                    </div>
                    <div>
                        <img src="@/assets/images/no_app.svg" />
                    </div>
                </div>
            </template>
        </LayoutContent>

        <el-card
            v-if="mysqlStatus != 'Running' && currentDB && !loading && maskShow && currentDB?.from === 'local'"
            class="mask-prompt"
        >
            <span>
                {{ $t('commons.service.serviceNotStarted', [mysqlName(currentDB.type)]) }}
            </span>
        </el-card>

        <DialogPro v-model="open" :title="$t('app.checkTitle')" size="small">
            <div class="flex justify-center items-center gap-2 flex-wrap">
                {{ $t('app.checkInstalledWarn', [dashboardName]) }}
                <el-link icon="Position" @click="getAppDetail" type="primary">
                    {{ $t('database.goInstall') }}
                </el-link>
            </div>
            <template #footer>
                <span class="dialog-footer">
                    <el-button @click="open = false">{{ $t('commons.button.cancel') }}</el-button>
                </span>
            </template>
        </DialogPro>

        <RootPasswordDialog ref="connRef" />
        <UploadDialog ref="uploadRef" />
        <OperateDialog @search="search" ref="dialogRef" />
        <Backups ref="dialogBackupRef" />
        <AppResources ref="checkRef"></AppResources>
        <DeleteDialog ref="deleteRef" @search="search" />
        <PortJumpDialog ref="dialogPortJumpRef" />
        <TerminalDialog ref="dialogTerminalRef" />
        <UserDialog ref="userRef" @search="search" />
        <BindDialog ref="bindRef" @search="onBindSearch" />
    </div>
</template>

<script lang="ts" setup>
import BindDialog from '@/views/database/mysql/bind/index.vue';
import UserDialog from '@/views/database/mysql/user/index.vue';
import OperateDialog from '@/views/database/mysql/create/index.vue';
import DeleteDialog from '@/views/database/mysql/delete/index.vue';
import RootPasswordDialog from '@/views/database/mysql/conn/index.vue';
import TerminalDialog from '@/components/terminal/database.vue';
import AppResources from '@/views/database/mysql/check/index.vue';
import AppStatus from '@/components/app-status/index.vue';
import Backups from '@/components/backup/index.vue';
import UploadDialog from '@/components/upload/index.vue';
import PortJumpDialog from '@/components/port-jump/index.vue';
import Tooltip from '@/components/tooltip/index.vue';
import { dateFormat } from '@/utils/date';
import { ElMessageBox } from 'element-plus';
import { onMounted, reactive, ref } from 'vue';
import {
    deleteCheckMysqlDB,
    listDatabases,
    loadDBFromRemote,
    searchMysqlGrantSummary,
    searchMysqlDBs,
    updateMysqlDescription,
} from '@/api/modules/database';
import i18n from '@/lang';
import { Database } from '@/api/interface/database';
import { App } from '@/api/interface/app';
import { getAppPort } from '@/api/modules/app';
import { MsgSuccess } from '@/utils/message';
import { useGlobalStore } from '@/composables/useGlobalStore';
import { useOperateNodeContext } from '@/composables/useOperateNodeContext';
import { routerToName, routerToNameWithParams, routerToNameWithQuery } from '@/utils/router';

const { currentNode, currentDB: globalCurrentDB, isAdminOrNodeAdmin, isMobile } = useGlobalStore();
useOperateNodeContext(currentNode);

const loading = ref(false);
const maskShow = ref(true);

const appKey = ref('mysql');
const appName = ref();

const isLoaded = ref(false);
const dbOptionsLocal = ref<Array<Database.DatabaseOption>>([]);
const dbOptionsRemote = ref<Array<Database.DatabaseOption>>([]);
const currentDB = ref<Database.DatabaseOption>();
const currentDBName = ref();

const bindRef = ref();
const userRef = ref();
const checkRef = ref();
const deleteRef = ref();
const dialogTerminalRef = ref();

const phpadminPort = ref();
const adminerPort = ref();
const dashboardName = ref();
const dashboardKey = ref();
const open = ref(false);

const appStatusRef = ref();

const dialogPortJumpRef = ref();

const data = ref<Database.MysqlDBInfo[]>([]);
let grantSummaryRequestID = 0;
const paginationConfig = reactive({
    cacheSizeKey: 'mysql-page-size',
    currentPage: 1,
    pageSize: Number(localStorage.getItem('mysql-page-size')) || 20,
    total: 0,
    orderBy: 'createdAt',
    order: 'null',
});
const searchName = ref();

const mysqlContainer = ref();
const mysqlStatus = ref();
const mysqlVersion = ref();

const dialogRef = ref();
const onOpenDialog = async () => {
    if (!currentDB.value?.database) {
        return;
    }
    let params = {
        from: currentDB.value.from,
        type: currentDB.value.type,
        database: currentDB.value.database,
    };
    dialogRef.value!.acceptParams(params);
};

const onCreateAction = async () => onOpenDialog();

const dialogBackupRef = ref();

const uploadRef = ref();

const connRef = ref();
const onChangeConn = async () => {
    if (!currentDB.value?.database) {
        return;
    }
    connRef.value!.acceptParams({
        from: currentDB.value.from,
        type: currentDB.value.type,
        database: currentDB.value.database,
    });
};

const mysqlName = (appType: string) => {
    if (appType === 'mysql' || appType === 'mysql-cluster') {
        return 'MySQL';
    } else {
        return 'MariaDB';
    }
};

const goRemoteDB = async () => {
    if (currentDB.value) {
        globalCurrentDB.value = currentDB.value.database;
    }
    routerToName('MySQL-Remote');
};

const goTerminal = () => {
    dialogTerminalRef.value.acceptParams({ databaseType: currentDB.value.type, database: currentDB.value.database });
};

const onSetting = async () => {
    if (currentDB.value) {
        globalCurrentDB.value = currentDB.value.database;
    }
    routerToNameWithParams('MySQL-Setting', { type: currentDB.value.type, database: currentDB.value.database });
};

const changeDatabase = async () => {
    for (const item of dbOptionsLocal.value) {
        if (item.database == currentDBName.value) {
            currentDB.value = item;
            globalCurrentDB.value = currentDB.value.database;
            appKey.value = item.type;
            appName.value = item.database;
            search();
            appStatusRef.value?.onCheck(appKey.value, appName.value);
            return;
        }
    }
    for (const item of dbOptionsRemote.value) {
        if (item.database == currentDBName.value) {
            maskShow.value = false;
            currentDB.value = item;
            globalCurrentDB.value = currentDB.value.database;
            break;
        }
    }
    search();
};

const search = async (column?: any) => {
    await searchDatabases(column);
};

const searchDatabases = async (column?: any) => {
    if (!currentDB.value?.database) {
        return;
    }
    const requestID = ++grantSummaryRequestID;
    paginationConfig.orderBy = column?.order ? column.prop : paginationConfig.orderBy;
    paginationConfig.order = column?.order ? column.order : paginationConfig.order;
    let params = {
        page: paginationConfig.currentPage,
        pageSize: paginationConfig.pageSize,
        info: searchName.value,
        database: currentDB.value.database,
        orderBy: paginationConfig.orderBy,
        order: paginationConfig.order,
    };
    const res = await searchMysqlDBs(params);
    if (requestID !== grantSummaryRequestID) {
        return;
    }
    data.value = res.data.items || [];
    paginationConfig.total = res.data.total;
    loadGrantSummary(data.value, requestID);
};

const loadGrantSummary = async (items: Database.MysqlDBInfo[], requestID: number) => {
    if (!currentDB.value?.database || items.length === 0) {
        return;
    }
    try {
        const res = await searchMysqlGrantSummary({
            database: currentDB.value.database,
            dbs: items.map((item) => item.name),
        });
        if (requestID !== grantSummaryRequestID) {
            return;
        }
        for (const item of data.value) {
            const users = res.data?.[item.name] || [];
            item.authorizedUsers = users;
        }
    } catch {
        return;
    }
};

const openUserDrawer = async () => {
    if (!currentDB.value?.database) {
        return;
    }
    userRef.value!.acceptParams({ database: currentDB.value.database });
};

const openAuthorizationManagement = (row: Database.MysqlDBInfo) => {
    if (!currentDB.value?.database) {
        return;
    }
    bindRef.value!.acceptParams({
        database: currentDB.value.database,
        db: row.name,
    });
};

const loadDB = async () => {
    ElMessageBox.confirm(i18n.global.t('database.loadFromRemoteHelper'), i18n.global.t('commons.msg.infoTitle'), {
        confirmButtonText: i18n.global.t('commons.button.confirm'),
        cancelButtonText: i18n.global.t('commons.button.cancel'),
        type: 'info',
    }).then(async () => {
        loading.value = true;
        let params = {
            from: currentDB.value.from,
            type: currentDB.value.type,
            database: currentDBName.value,
        };
        await loadDBFromRemote(params)
            .then(() => {
                loading.value = false;
                search();
            })
            .catch(() => {
                loading.value = false;
            });
    });
};

const goRouter = async (target: string) => {
    if (target === 'app') {
        routerToNameWithQuery('AppAll', { install: 'mysql' });
        return;
    }
    routerToName('MySQL-Remote');
};

const onChange = async (info: any) => {
    await updateMysqlDescription({ id: info.id, description: info.description });
    MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
};

const goDashboard = async (name: string) => {
    if (name === 'phpMyAdmin') {
        if (phpadminPort.value === 0) {
            dashboardName.value = 'phpMyAdmin';
            dashboardKey.value = 'phpmyadmin';
            open.value = true;
            return;
        }
        dialogPortJumpRef.value.acceptParams({ port: phpadminPort.value });
        return;
    }
    if (adminerPort.value === 0) {
        dashboardName.value = 'Adminer';
        dashboardKey.value = 'adminer';
        open.value = true;
        return;
    }
    dialogPortJumpRef.value.acceptParams({ port: adminerPort.value });
};

const getAppDetail = () => {
    routerToNameWithQuery('AppAll', { install: dashboardKey.value });
};

const loadPhpMyAdminPort = async () => {
    const res = await getAppPort('phpmyadmin', '');
    phpadminPort.value = res.data;
};

const loadAdminerPort = async () => {
    const res = await getAppPort('adminer', '');
    adminerPort.value = res.data;
};

const checkExist = (data: App.CheckInstalled) => {
    mysqlStatus.value = data.status;
    mysqlVersion.value = data.version;
    mysqlContainer.value = data.containerName;
};

const loadDBOptions = async () => {
    try {
        const res = await listDatabases('mysql,mariadb,mysql-cluster');
        let datas = res.data || [];
        dbOptionsLocal.value = [];
        dbOptionsRemote.value = [];
        currentDBName.value = globalCurrentDB.value;
        for (const item of datas) {
            if (currentDBName.value && item.database === currentDBName.value) {
                currentDB.value = item;
                if (item.from === 'local') {
                    appKey.value = item.type;
                    appName.value = item.database;
                }
            }
            if (item.from === 'local') {
                dbOptionsLocal.value.push(item);
            } else {
                dbOptionsRemote.value.push(item);
            }
        }
        if (currentDB.value) {
            if (currentDB.value?.from === 'remote') {
                maskShow.value = false;
            }
            search();
            return;
        }
        if (dbOptionsLocal.value.length !== 0) {
            currentDB.value = dbOptionsLocal.value[0];
            currentDBName.value = dbOptionsLocal.value[0].database;
            appKey.value = dbOptionsLocal.value[0].type;
            appName.value = dbOptionsLocal.value[0].database;
        }
        if (!currentDB.value && dbOptionsRemote.value.length !== 0) {
            currentDB.value = dbOptionsRemote.value[0];
            currentDBName.value = dbOptionsRemote.value[0].database;
        }
        if (currentDB.value) {
            search();
        }
        if (currentDB.value?.from === 'remote') {
            maskShow.value = false;
        }
    } finally {
        isLoaded.value = true;
    }
};
const onDelete = async (row: Database.MysqlDBInfo) => {
    let param = {
        id: row.id,
        type: currentDB.value.type,
        database: currentDBName.value,
    };
    const res = await deleteCheckMysqlDB(param);
    if (res.data && res.data.length > 0) {
        checkRef.value.acceptParams({ items: res.data });
    } else {
        deleteRef.value.acceptParams({
            id: row.id,
            type: currentDB.value.type,
            database: currentDBName.value,
            name: row.name,
        });
    }
};

const buttons = [
    {
        label: i18n.global.t('database.backupList'),
        permission: true,
        disabled: (row: Database.MysqlDBInfo) => {
            return row.isDelete;
        },
        click: (row: Database.MysqlDBInfo) => {
            let params = {
                type: currentDB.value.type,
                name: currentDBName.value,
                detailName: row.name,
            };
            dialogBackupRef.value!.acceptParams(params);
        },
    },
    {
        label: i18n.global.t('database.loadBackup'),
        permission: true,
        disabled: (row: Database.MysqlDBInfo) => {
            return row.isDelete;
        },
        click: (row: Database.MysqlDBInfo) => {
            let params = {
                type: currentDB.value.type,
                name: currentDBName.value,
                detailName: row.name,
                remark: row.format,
            };
            uploadRef.value!.acceptParams(params);
        },
    },
    {
        label: i18n.global.t('commons.button.delete'),
        permission: true,
        click: (row: Database.MysqlDBInfo) => {
            onDelete(row);
        },
    },
];

const onBindSearch = async () => {
    await search();
};

onMounted(() => {
    loadDBOptions();
    loadPhpMyAdminPort();
    loadAdminerPort();
});
</script>

<style lang="scss" scoped>
.iconInTable {
    margin-left: 5px;
    margin-top: 3px;
}
.jumpAdd {
    margin-top: 10px;
    margin-left: 15px;
    margin-bottom: 5px;
    font-size: 12px;
}
.tagClass {
    float: right;
    font-size: 12px;
    margin-top: 5px;
}
.optionClass {
    min-width: 350px;
}
</style>
