import TaskManagementMixin from './mixin/TaskManagementMixin.js';


export default {
    mixins: [TaskManagementMixin],

    props: {
        serverData: {
            type: Object,
            required: true
        },
        xhrUrl: {
            type: String,
            required: true
        },
        fromAdmin: {
            type: Boolean,
            default: false,
            required: false
        }
    },

    data() {
        return {
            backups: [],
            backupMeta: null,
            showCreateDialog: false,
            selectedBackup: null,
            createData: {},
            pageSearchBar: {
                backups: {
                    show: false,
                    search: ''
                }
            }
        };
    },

    template: `
        <div>
            <alert-modal ref="confirmDelete"></alert-modal>
            <alert-modal ref="confirmRestore"></alert-modal>

            <div class="alert alert-info" v-if="backupMeta && backupMeta.maxBackups > 0">
                <div class="row">
                    <div class="col-sm-9">
                        <strong style="margin-right: 5px;">{{ jsToLang('card.backups.quota.usage') }}</strong>
                        <span>{{ backups.length }} {{ jsToLang('card.backups.quota.of') }} {{ backupMeta.maxBackups }} {{ jsToLang('card.backups.quota.backups') }}</span>
                    </div>

                    <div class="col-sm-3 text-right" v-if="isQuotaReached">
                        <span class="label label-danger">
                            {{ jsToLang('card.backups.quota.limit_reached') }}
                        </span>
                    </div>
                </div>
            </div>

            <div class="panel panel-default card">
                <div class="panel-heading card-header">
                    <div class="row">
                        <div class="col-md-4">
                            <b style="font-size: 20px; font-weight: 500;">{{ jsToLang('card.backups.title') }}</b>
                        </div>

                        <div class="col-md-8 text-right">
                            <button class="btn btn-default" :class="getBsVersion !== 3 ? 'btn-sm' : ''" @click="pageSearchBar.backups.show = true" v-if="!pageSearchBar.backups.show">
                                <i :class="faIconRepo('fa-search')"></i>
                                {{ jsToLang('generic.button.search') }}
                            </button>

                            <span class="input-group" v-if="pageSearchBar.backups.show" style="display:inline-flex; width:auto; vertical-align:middle; white-space:nowrap;">
                                <input type="text" class="form-control" :class="getBsVersion !== 3 ? 'form-control-sm' : ''" v-model="pageSearchBar.backups.search" :placeholder="jsToLang('generic.text.search')" style="width:200px; flex:0 0 auto;">

                                <span class="input-group-append input-group-btn">
                                    <button class="btn btn-default" :class="getBsVersion !== 3 ? 'btn-sm' : ''" type="button" @click="pageSearchBar.backups.show = false; pageSearchBar.backups.search = ''">
                                        <i :class="faIconRepo('fa-times')"></i>
                                    </button>
                                </span>
                            </span>

                            <d-button :without-margin-right="true" class="btn btn-default" :class="getBsVersion !== 3 ? 'btn-sm' : ''" @click.native="refreshList()" :disabled="$simpleStore.getLoader('getServerBackups') || isAnyOperationRunning"
                                      :loading="$simpleStore.getLoader('getServerBackups')">
                                <i v-if="!$simpleStore.getLoader('getServerBackups')" :class="faIconRepo('fa-refresh')"></i>
                            </d-button>

                            <button v-if="dCan('servers.backups.store') && !isBackupQuotaZero && backupMeta" class="btn btn-primary" :class="getBsVersion !== 3 ? 'btn-sm' : ''" @click.prevent="openCreateDialog"
                                    :disabled="isAnyOperationRunning || isQuotaReached">
                                <template v-if="!isCreating">
                                    <i :class="faIconRepo('fa-plus')" style="margin-right: 5px;"></i>
                                    {{ jsToLang('card.backups.button.create') }}
                                </template>
                                <template v-else>
                                    <i :class="faIconRepo('fa-refresh-spin')" style="margin-right: 5px;"></i>
                                    {{ jsToLang('card.backups.task.creating') }} ({{ getCreateTaskProgress() }}%)
                                </template>
                            </button>
                        </div>
                    </div>
                </div>

                <div class="panel-body card-body" style="padding-top: 0px; padding-bottom: 0px;">
                    <div class="row">
                        <div class="col-md-12" style="padding-left: 5px; padding-right: 5px; padding-top: 10px;">
                            <table class="table ds-table-no-top-border ds-table-td-vertical" style="margin-bottom: 0px;" :class="fromAdmin ? 'table-responsive' : ''">
                                <thead>
                                <tr style="display: revert !important;">
                                    <th>{{ jsToLang('card.backups.table.name') }}</th>
                                    <th>{{ jsToLang('card.backups.table.size') }}</th>
                                    <th>{{ jsToLang('card.backups.table.created') }}</th>
                                    <th>{{ jsToLang('card.backups.table.status') }}</th>
                                    <th class="text-right">{{ jsToLang('card.backups.table.actions') }}</th>
                                </tr>
                                </thead>
                                <tbody>
                                <tr style="display: revert !important;" v-for="backup in filteredBackups" :key="backup.backupId">
                                    <td>
                                        <span data-toggle="dynamic-tooltip" :title="backup.name">
                                            <strong>{{ truncateLong(backup.name, 27) }}</strong>
                                        </span>
                                    </td>
                                    <td>{{ formatByteToNice(backup.size) }}</td>
                                    <td>{{ convertDateTime(backup.created) }}</td>
                                    <td>
                                        <template v-if="isBackupDeleting(backup.backupId) && dCan('tasks.show')">
                                            <span class="label label-danger">
                                                {{ jsToLang('card.backups.task.deleting') }} ({{ getDeleteTaskProgress(backup.backupId) }}%)
                                            </span>
                                        </template>
                                        <template v-else-if="isBackupRestoring(backup.backupId) && dCan('tasks.show')">
                                            <span class="label label-warning">
                                                {{ jsToLang('card.backups.task.restoring') }} ({{ getRestoreTaskProgress() }}%)
                                            </span>
                                        </template>
                                        <template v-else>
                                            <span class="label label-success">{{ jsToLang('card.backups.status.success') }}</span>
                                        </template>
                                    </td>
                                    <td class="text-right" style="white-space: nowrap;">
                                        <button v-if="dCan('servers.backups.restore')" class="btn btn-sm btn-warning" @click.prevent="restoreBackup(backup)" :disabled="isBackupRestoring(backup.backupId) || isAnyOperationRunning"
                                                :title="jsToLang('card.backups.button.restore')">
                                            <i :class="isBackupRestoring(backup.backupId) ? faIconRepo('fa-refresh-spin') : faIconRepo('fa-undo')"></i>
                                        </button>
                                        <button v-if="dCan('servers.backups.destroy')" class="btn btn-sm btn-danger" @click.prevent="confirmDelete(backup)" :disabled="isBackupDeleting(backup.backupId) || isAnyOperationRunning">
                                            <i :class="isBackupDeleting(backup.backupId) ? faIconRepo('fa-refresh-spin') : faIconRepo('fa-trash')"></i>
                                        </button>
                                    </td>
                                </tr>
                                <tr style="display: revert !important;" v-if="filteredBackups.length === 0">
                                    <td colspan="6" class="text-center text-muted">
                                        <span v-if="$simpleStore.getLoader('getServerBackups')">
                                            <div class="text-center">
                                                <i :class="faIconRepo('fa-refresh-spin')" style="font-size: 24px;"></i>
                                                <div style="margin-top: 5px;">{{ jsToLang('generic.text.loading') }}</div>
                                            </div>
                                        </span>
                                        <span v-else>
                                            {{ jsToLang('card.backups.table.no_backups') }}
                                        </span>
                                    </td>
                                </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>

                <div class="modal ds-modal fade" :id="'createBackupModal_' + _uid" tabindex="-1" role="dialog">
                    <div class="modal-dialog" role="document">
                        <div class="modal-content">
                            <div class="modal-header bg-primary text-white">
                                <h5 class="modal-title">{{ jsToLang('card.backups.modal.create.title') }}</h5>
                            </div>
                            <div class="modal-body">
                                <template v-if="!backupMeta || !backupMeta.ui || !backupMeta.ui.create">
                                    <div class="text-center">
                                        <i :class="faIconRepo('fa-refresh-spin')" style="font-size: 24px;"></i>
                                        <div style="margin-top: 10px;">{{ jsToLang('generic.text.loading') }}</div>
                                    </div>
                                </template>
                                <template v-else>
                                    <div class="form-group" v-for="(field, key) in backupMeta.ui.create" :key="key">
                                        <label v-if="field.type !== 'checkbox'">
                                            {{ field.label }}
                                            <small v-if="!field.required" class="text-muted">({{ jsToLang('generic.text.optional') }})</small>
                                        </label>

                                        <select v-if="field.type === 'select'" class="form-control" v-model="createData[key]">
                                            <option v-for="item in getSelectItems(field, key)" :key="item.value" :value="item.value">
                                                {{ item.text }}
                                            </option>
                                        </select>

                                        <input v-if="field.type === 'text'" type="text" class="form-control" v-model="createData[key]" :maxlength="field.maxLength" :placeholder="field.placeholder">

                                        <div v-if="field.type === 'checkbox'" class="checkbox">
                                            <label>
                                                <input type="checkbox" v-model="createData[key]">
                                                {{ field.label }}
                                                <i v-if="field.tooltip" :class="faIconRepo('fa-info-circle')" style="margin-left: 5px;" :title="field.tooltip" data-toggle="tooltip"></i>
                                            </label>
                                        </div>
                                    </div>
                                </template>
                            </div>
                            <div class="modal-footer panel-footer card-footer">
                                <button type="button" class="btn btn-secondary pull-left float-left" data-dismiss="modal">
                                    {{ jsToLang('card.backups.button.cancel') }}
                                </button>
                                <button type="button" class="btn btn-primary pull-right float-right" @click.prevent="createBackup" :disabled="!isCreateFormValid || $simpleStore.getLoader('createServerBackup')">
                                    <i :class="$simpleStore.getLoader('createServerBackup') ? faIconRepo('fa-refresh-spin') : faIconRepo('fa-check')" style="margin-right: 5px;"></i>
                                    {{ jsToLang('card.backups.button.create') }}
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    `,

    computed: {
        filteredBackups() {
            if (!this.pageSearchBar.backups.search) {
                return this.backups;
            }
            const search = this.pageSearchBar.backups.search.toLowerCase();
            return this.backups.filter(backup => {
                return backup.name.toLowerCase().includes(search) || (backup.description && backup.description.toLowerCase().includes(search));
            });
        },

        isQuotaReached() {
            return this.backupMeta && this.backupMeta.maxBackups > 0 && this.backups.length >= this.backupMeta.maxBackups;
        },

        isBackupQuotaZero() {
            return this.backupMeta?.maxBackups === 0;
        },

        isCreateFormValid() {
            if (!this.backupMeta?.ui?.create) {
                return false;
            }

            for (const [key, field] of Object.entries(this.backupMeta.ui.create)) {
                if (field?.required) {
                    const value = this.createData[key];
                    if (value === undefined || value === null || value === '') {
                        return false;
                    }

                    if (field.type === 'text' && typeof value === 'string' && value.trim() === '') {
                        return false;
                    }
                }
            }

            return true;
        }
    },

    methods: {
        async areBackupsAvailable() {
            if (!this.dCan('servers.backups.available') || !this.dCan('servers.backups.index')) {
                return false;
            }

            try {
                const response = await this.featureAvailabilityChecker('getServerBackupsAvailable');

                return response.available;
            } catch (e) {
                console.log(e);
                return false;
            }
        },

        async refreshList(withoutLoadingState = false) {
            await this.getBackupList(withoutLoadingState);
        },

        async getBackupList(withoutLoadingState = false) {
            if (!this.dCan('servers.backups.index')) {
                return;
            }

            if (!withoutLoadingState) {
                this.$simpleStore.addLoader('getServerBackups');
            }

            try {
                const response = await axios.get(this.xhrUrl + 'getServerBackups');
                const data = response.data;

                if (data) {
                    this.backups = data.backups || [];
                    this.activeTasks = data.activeTasks || {};

                    const isFirstLoad = !this.backupMeta && data.meta;
                    this.backupMeta = data.meta || null;

                    if (isFirstLoad && this.backupMeta?.ui?.create) {
                        this.initializeCreateData();
                    }

                    this.updateLocalFlags();

                    if (data.notifications && data.notifications.length > 0) {
                        data.notifications.forEach(notification => {
                            if (notification.type === 'success') {
                                this.successNotificationFlash(notification.message);

                                if (notification.action === 'restoreBackup') {
                                    setTimeout(() => {
                                        this.$emit('refresh-power');
                                    }, 1000);
                                }
                            } else if (notification.type === 'error') {
                                this.errorNotificationFlash(notification.message, false, true);
                            }
                        });
                    }

                    this.handleActiveTasksPolling();
                }
            } catch (error) {
                this.errorNotificationFlash(error.response?.data || 'Failed to load backups');
            } finally {
                if (!withoutLoadingState) {
                    this.$simpleStore.delLoader('getServerBackups');
                }
            }
        },

        updateLocalFlags() {
            this.isCreating = this.activeTasks.activeCreateBackupTask && this.isTaskActive(this.activeTasks.activeCreateBackupTask.status);
            this.isAnyDeleting = this.activeTasks.activeDeleteBackupTasks?.some(task => this.isTaskActive(task.status)) || false;
            this.isAnyRestoring = this.activeTasks.activeRestoreBackupTask && this.isTaskActive(this.activeTasks.activeRestoreBackupTask.status);
        },

        handleActiveTasksPolling() {
            if (!this.dCan || !this.dCan('tasks.show')) {
                return false;
            }

            const createTask = this.activeTasks.activeCreateBackupTask;

            if (createTask && this.isTaskActive(createTask.status)) {
                if (!this.pollingTimeouts.create) {
                    this.pollTaskStatus(createTask.taskId, 'create');
                }
            }

            const deleteTasks = this.activeTasks.activeDeleteBackupTasks;

            if (deleteTasks && deleteTasks.length > 0) {
                deleteTasks.forEach(deleteTask => {
                    if (this.isTaskActive(deleteTask.status) && !this.pollingTimeouts.delete[deleteTask.taskId]) {
                        this.pollTaskStatus(deleteTask.taskId, 'delete', deleteTask.backupId);
                    }
                });
            }

            const restoreTask = this.activeTasks.activeRestoreBackupTask;
            if (restoreTask && this.isTaskActive(restoreTask.status)) {
                if (!this.pollingTimeouts.restore) {
                    this.pollTaskStatus(restoreTask.taskId, 'restore', restoreTask.backupId);
                }
            }
        },

        initializeCreateData() {
            if (this.backupMeta?.ui?.create) {
                const newData = {};

                Object.entries(this.backupMeta.ui.create).forEach(([key, field]) => {
                    if (field.default !== undefined) {
                        newData[key] = field.default;
                    } else if (field.type === 'checkbox') {
                        newData[key] = false;
                    } else {
                        newData[key] = '';
                    }
                });

                this.createData = newData;
            }
        },

        getSelectItems(field, key) {
            if (Array.isArray(field.options)) {
                return field.options.map(opt => {
                    if (typeof opt === 'object') {
                        return {
                            value: opt.id || opt.value || opt,
                            text: opt.name || opt.text || opt.label || opt
                        };
                    }
                    return {
                        value: opt,
                        text: opt
                    };
                });
            } else if (typeof field.options === 'object') {
                return Object.entries(field.options).map(([value, label]) => ({
                    value: value,
                    text: label
                }));
            }

            return [];
        },

        openCreateDialog() {
            this.initializeCreateData();
            this.showCreateDialog = true;
            jQuery('#createBackupModal_' + this._uid).modal('show');
        },

        closeCreateDialog() {
            this.showCreateDialog = false;
            this.createData = {};
            jQuery('#createBackupModal_' + this._uid).modal('hide');
        },

        async createBackup() {
            this.isCreating = true;

            this.$simpleStore.addLoader('createServerBackup');

            try {
                const response = await axios.post(this.xhrUrl + 'createServerBackup', {
                    options: this.createData
                });

                if (response.data) {
                    this.closeCreateDialog();

                    if (response.data.result === 'queued' && response.data.taskId) {
                        this.activeTasks.activeCreateBackupTask = {
                            status: 'pending',
                            taskId: response.data.taskId,
                            progress: 0
                        };
                        this.pollTaskStatus(response.data.taskId, 'create');
                    } else if (response.data.result === 'success' || response.data.result === 'failed') {
                        this.isCreating = false;
                        await this.refreshList();
                    } else {
                        this.isCreating = false;
                    }
                } else {
                    this.isCreating = false;
                }
            } catch (error) {
                this.isCreating = false;
                this.errorNotificationFlash(error.response?.data || 'Failed to create backup');
            } finally {
                this.$simpleStore.delLoader('createServerBackup');
            }
        },

        async confirmDelete(backup) {
            this.selectedBackup = backup;

            const confirmed = await this.$refs.confirmDelete.open(this.jsToLang('card.backups.modal.delete.title'), this.jsToLang('card.backups.modal.delete.confirm'), '', this.jsToLang('card.backups.button.delete'));

            if (confirmed) {
                await this.deleteBackup();
            }
        },

        async deleteBackup() {
            this.isAnyDeleting = true;

            const backupIndex = this.backups.findIndex(b => b.backupId === this.selectedBackup.backupId);

            if (backupIndex !== -1) {
                this.$set(this.backups[backupIndex], 'isDeleting', true);
            }

            let isQueued = false;

            try {
                const response = await axios.post(this.xhrUrl + 'deleteServerBackup', {
                    backupId: this.selectedBackup.backupId
                });

                if (response.data) {
                    if (response.data.result === 'queued' && response.data.taskId) {
                        isQueued = true;

                        if (!this.activeTasks.activeDeleteBackupTasks) {
                            this.activeTasks.activeDeleteBackupTasks = [];
                        }

                        this.activeTasks.activeDeleteBackupTasks.push({
                            backupId: this.selectedBackup.backupId,
                            status: 'pending',
                            taskId: response.data.taskId,
                            progress: 0
                        });

                        this.pollTaskStatus(response.data.taskId, 'delete', this.selectedBackup.backupId);
                    } else if (response.data.result === 'success' || response.data.result === 'failed') {
                        await this.refreshList();
                    }
                }
            } catch (error) {
                this.errorNotificationFlash(error.response?.data || 'Failed to delete backup');
            } finally {
                if (!isQueued) {
                    this.isAnyDeleting = false;

                    if (backupIndex !== -1) {
                        this.$set(this.backups[backupIndex], 'isDeleting', false);
                    }
                }

                this.selectedBackup = null;
            }
        },

        async restoreBackup(backup) {
            this.selectedBackup = backup;

            const confirmed = await this.$refs.confirmRestore.open(this.jsToLang('card.backups.modal.restore.title'), this.jsToLang('card.backups.modal.restore.confirm'), '', this.jsToLang('card.backups.button.restore'));

            if (confirmed) {
                await this.performRestore();
            }
        },

        async performRestore() {
            this.isAnyRestoring = true;

            const backupIndex = this.backups.findIndex(b => b.backupId === this.selectedBackup.backupId);

            if (backupIndex !== -1) {
                this.$set(this.backups[backupIndex], 'isRestoring', true);
            }

            let isQueued = false;

            try {
                const response = await axios.post(this.xhrUrl + 'restoreServerBackup', {
                    backupId: this.selectedBackup.backupId
                });

                if (response.data) {
                    if (response.data.result === 'queued' && response.data.taskId) {
                        isQueued = true;

                        this.activeTasks.activeRestoreBackupTask = {
                            backupId: this.selectedBackup.backupId,
                            status: 'pending',
                            taskId: response.data.taskId,
                            progress: 0
                        };

                        this.pollTaskStatus(response.data.taskId, 'restore', this.selectedBackup.backupId);
                    } else if (response.data.result === 'success' || response.data.result === 'failed') {
                        await this.refreshList();
                    }
                }
            } catch (error) {
                this.errorNotificationFlash(error.response?.data || 'Failed to restore backup');
            } finally {
                if (!isQueued) {
                    this.isAnyRestoring = false;

                    if (backupIndex !== -1) {
                        this.$set(this.backups[backupIndex], 'isRestoring', false);
                    }
                }

                this.selectedBackup = null;
            }
        },

        isBackupDeleting(backupId) {
            const backup = this.backups.find(b => b.backupId === backupId);
            if (backup?.isDeleting) {
                return true;
            }

            return this.activeTasks.activeDeleteBackupTasks?.some(task => task.backupId === backupId && this.isTaskActive(task.status)) || false;
        },

        isBackupRestoring(backupId) {
            const backup = this.backups.find(b => b.backupId === backupId);
            if (backup?.isRestoring) {
                return true;
            }

            return this.activeTasks.activeRestoreBackupTask?.backupId === backupId && this.isTaskActive(this.activeTasks.activeRestoreBackupTask?.status);
        },

        loadIfVisible() {
            this.getBackupList();
        }
    },

    mounted() {
    }
};