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 {
            snapshots: [],
            snapshotMeta: null,
            showCreateDialog: false,
            selectedSnapshot: null,
            createData: {},
            pageSearchBar: {
                snapshots: {
                    show: false,
                    search: ''
                }
            }
        };
    },

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

            <div class="alert alert-info" v-if="snapshotMeta && snapshotMeta.maxSnapshots > 0">
                <div class="row">
                    <div class="col-sm-9">
                        <strong>{{ jsToLang('card.snapshots.quota.usage') }}</strong>
                        <span>
                            {{ snapshots.length }} {{ jsToLang('card.snapshots.quota.of') }} {{ snapshotMeta.maxSnapshots }} {{ jsToLang('card.snapshots.quota.snapshots') }}
                        </span>
                    </div>

                    <div class="col-sm-3 text-right" v-if="isQuotaReached">
                        <span class="label label-danger">
                            {{ jsToLang('card.snapshots.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.snapshots.title') }}</b>
                        </div>

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

                            <span class="input-group" v-if="pageSearchBar.snapshots.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.snapshots.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.snapshots.show = false; pageSearchBar.snapshots.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('getServerSnapshots') || isAnyOperationRunning"
                                      :loading="$simpleStore.getLoader('getServerSnapshots')">
                                <i v-if="!$simpleStore.getLoader('getServerSnapshots')" :class="faIconRepo('fa-refresh')"></i>
                            </d-button>

                            <button v-if="dCan('servers.snapshots.store') && !isSnapshotQuotaZero && snapshotMeta" 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.snapshots.button.create') }}
                                </template>

                                <template v-else>
                                    <i :class="faIconRepo('fa-refresh-spin')" style="margin-right: 5px;"></i>
                                    {{ jsToLang('card.snapshots.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.snapshots.table.name') }}</th>
                                    <th>{{ jsToLang('card.snapshots.table.created') }}</th>
                                    <th class="text-center">{{ jsToLang('card.snapshots.table.memory') }}</th>
                                    <th>{{ jsToLang('card.snapshots.table.status') }}</th>
                                    <th class="text-right">{{ jsToLang('card.snapshots.table.actions') }}</th>
                                </tr>
                                </thead>
                                <tbody>
                                <tr style="display: revert !important;" v-for="snapshot in filteredSnapshots" :key="snapshot.snapshotId">
                                    <td>
                                        <div :style="{ paddingLeft: (snapshot.depth * 10) + 'px' }">
                                            <i v-if="snapshot.depth > 0" :class="faIconRepo('fa-level-up-90')" style="margin-right: 5px; color: #999;"></i>

                                            <span data-toggle="dynamic-tooltip" :title="snapshot.name">
                                                <strong>{{ truncateLong(snapshot.name, 20) }}</strong>

                                                <span v-if="snapshot.isCurrent" class="label label-success" style="margin-left: 5px;">
                                                    {{ jsToLang('card.snapshots.label.current') }}
                                                </span>
                                            </span>

                                            <div v-if="snapshot.description">
                                                <small data-toggle="dynamic-tooltip" :title="snapshot.description">{{ truncateLong(snapshot.description, 30) }}</small>
                                            </div>
                                        </div>
                                    </td>
                                    <td>{{ convertDateTime(snapshot.created) }}</td>
                                    <td class="text-center">
                                        <i :class="snapshot.includesMemory ? faIconRepo('fa-check-circle') : faIconRepo('fa-times-circle')" :style="{ color: snapshot.includesMemory ? '#5cb85c' : '#999' }"></i>
                                    </td>
                                    <td>
                                        <template v-if="isSnapshotDeleting(snapshot.snapshotId) && dCan('tasks.show')">
                                            <span class="label label-danger">
                                                {{ jsToLang('card.snapshots.task.deleting') }} ({{ getDeleteTaskProgress(snapshot.snapshotId) }}%)
                                            </span>
                                        </template>

                                        <template v-else-if="isSnapshotRollingBack(snapshot.snapshotId) && dCan('tasks.show')">
                                            <span class="label label-warning">
                                                {{ jsToLang('card.snapshots.task.rolling_back') }} ({{ getRollbackTaskProgress() }}%)
                                            </span>
                                        </template>

                                        <template v-else>
                                            <span class="label label-success">{{ jsToLang('card.snapshots.status.success') }}</span>
                                        </template>
                                    </td>
                                    <td class="text-right" style="white-space: nowrap;">
                                        <button v-if="dCan('servers.snapshots.rollback')" class="btn btn-sm btn-warning" @click.prevent="rollbackSnapshot(snapshot)" :disabled="isSnapshotRollingBack(snapshot.snapshotId) || isAnyOperationRunning"
                                                :title="jsToLang('card.snapshots.button.rollback')">
                                            <i :class="isSnapshotRollingBack(snapshot.snapshotId) ? faIconRepo('fa-refresh-spin') : faIconRepo('fa-undo')"></i>
                                        </button>

                                        <button v-if="dCan('servers.snapshots.destroy')" class="btn btn-sm btn-danger" @click.prevent="confirmDelete(snapshot)" :disabled="isSnapshotDeleting(snapshot.snapshotId) || isAnyOperationRunning">
                                            <i :class="isSnapshotDeleting(snapshot.snapshotId) ? faIconRepo('fa-refresh-spin') : faIconRepo('fa-trash')"></i>
                                        </button>
                                    </td>
                                </tr>
                                <tr style="display: revert !important;" v-if="filteredSnapshots.length === 0">
                                    <td colspan="6" class="text-center text-muted">
                                        <span v-if="$simpleStore.getLoader('getServerSnapshots')">
                                            <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.snapshots.table.no_snapshots') }}
                                        </span>
                                    </td>
                                </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>

                <div class="modal ds-modal fade" :id="'createSnapshotModal_' + _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.snapshots.modal.create.title') }}</h5>
                            </div>
                            <div class="modal-body">
                                <template v-if="!snapshotMeta || !snapshotMeta.ui || !snapshotMeta.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 snapshotMeta.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.snapshots.button.cancel') }}
                                </button>

                                <button type="button" class="btn btn-primary pull-right float-right" @click.prevent="createSnapshot" :disabled="!isCreateFormValid || $simpleStore.getLoader('createServerSnapshot')">
                                    <i :class="$simpleStore.getLoader('createServerSnapshot') ? faIconRepo('fa-refresh-spin') : faIconRepo('fa-check')" style="margin-right: 5px;"></i>
                                    {{ jsToLang('card.snapshots.button.create') }}
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    `,

    computed: {
        filteredSnapshots() {
            if (!this.pageSearchBar.snapshots.search) {
                return this.processedSnapshots;
            }
            const search = this.pageSearchBar.snapshots.search.toLowerCase();
            return this.processedSnapshots.filter(snapshot => {
                return snapshot.name.toLowerCase().includes(search) || (snapshot.description && snapshot.description.toLowerCase().includes(search));
            });
        },

        processedSnapshots() {
            const snapshotMap = new Map();
            const processed = [];

            this.snapshots.forEach(snapshot => {
                snapshotMap.set(snapshot.snapshotId, {
                    ...snapshot,
                    children: [],
                    depth: 0,
                    parentName: null,
                    isLastChild: false
                });
            });

            snapshotMap.forEach(snapshot => {
                if (snapshot.parent && snapshotMap.has(snapshot.parent)) {
                    const parent = snapshotMap.get(snapshot.parent);
                    parent.children.push(snapshot.snapshotId);

                    snapshot.parentName = parent.name;
                }
            });

            const addToProcessed = (snapshotId, depth = 0, isLastChild = false) => {
                const snapshot = snapshotMap.get(snapshotId);
                if (!snapshot) {
                    return;
                }

                snapshot.depth = depth;
                snapshot.isLastChild = isLastChild;
                processed.push(snapshot);

                const sortedChildren = snapshot.children.map(childId => snapshotMap.get(childId)).filter(child => child).sort((a, b) => (b.created || 0) - (a.created || 0));

                sortedChildren.forEach((child, index) => {
                    addToProcessed(child.snapshotId, depth + 1, index === sortedChildren.length - 1);
                });
            };

            const rootSnapshots = [];
            snapshotMap.forEach(snapshot => {
                if (!snapshot.parent || !snapshotMap.has(snapshot.parent)) {
                    rootSnapshots.push(snapshot);
                }
            });

            rootSnapshots.sort((a, b) => (b.created || 0) - (a.created || 0)).forEach((root, index) => {
                addToProcessed(root.snapshotId, 0, index === rootSnapshots.length - 1);
            });

            return processed;
        },

        isQuotaReached() {
            return this.snapshotMeta && this.snapshotMeta.maxSnapshots > 0 && this.snapshots.length >= this.snapshotMeta.maxSnapshots;
        },

        isSnapshotQuotaZero() {
            return this.snapshotMeta?.maxSnapshots === 0;
        },

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

            for (const [key, field] of Object.entries(this.snapshotMeta.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 areSnapshotsAvailable() {
            if (!this.dCan('servers.snapshots.available') || !this.dCan('servers.snapshots.index')) {
                return false;
            }

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

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

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

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

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

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

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

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

                    if (isFirstLoad && this.snapshotMeta?.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 === 'rollbackSnapshot') {
                                    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 snapshots');
            } finally {
                if (!withoutLoadingState) {
                    this.$simpleStore.delLoader('getServerSnapshots');
                }
            }
        },

        updateLocalFlags() {
            this.isCreating = this.activeTasks.activeCreateSnapshotTask && this.isTaskActive(this.activeTasks.activeCreateSnapshotTask.status);
            this.isAnyDeleting = this.activeTasks.activeDeleteSnapshotTasks?.some(task => this.isTaskActive(task.status)) || false;
            this.isAnyRollingBack = this.activeTasks.activeRollbackSnapshotTask && this.isTaskActive(this.activeTasks.activeRollbackSnapshotTask.status);
        },

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

            const createTask = this.activeTasks.activeCreateSnapshotTask;

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

            const deleteTasks = this.activeTasks.activeDeleteSnapshotTasks;

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

            const rollbackTask = this.activeTasks.activeRollbackSnapshotTask;
            if (rollbackTask && this.isTaskActive(rollbackTask.status)) {
                if (!this.pollingTimeouts.rollback) {
                    this.pollTaskStatus(rollbackTask.taskId, 'rollback', rollbackTask.snapshotId);
                }
            }
        },

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

                Object.entries(this.snapshotMeta.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('#createSnapshotModal_' + this._uid).modal('show');
        },

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

        async createSnapshot() {
            this.isCreating = true;

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

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

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

                    if (response.data.result === 'queued' && response.data.taskId) {
                        this.activeTasks.activeCreateSnapshotTask = {
                            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 snapshot');
            } finally {
                this.$simpleStore.delLoader('createServerSnapshot');
            }
        },

        async confirmDelete(snapshot) {
            this.selectedSnapshot = snapshot;

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

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

        async deleteSnapshot() {
            this.isAnyDeleting = true;

            const snapshotIndex = this.snapshots.findIndex(s => s.snapshotId === this.selectedSnapshot.snapshotId);

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

            let isQueued = false;

            try {
                const response = await axios.post(this.xhrUrl + 'deleteServerSnapshot', {
                    snapshotId: this.selectedSnapshot.snapshotId
                });

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

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

                        this.activeTasks.activeDeleteSnapshotTasks.push({
                            snapshotId: this.selectedSnapshot.snapshotId,
                            status: 'pending',
                            taskId: response.data.taskId,
                            progress: 0
                        });

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

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

                this.selectedSnapshot = null;
            }
        },

        async rollbackSnapshot(snapshot) {
            this.selectedSnapshot = snapshot;

            const confirmed = await this.$refs.confirmRollback.open(this.jsToLang('card.snapshots.modal.rollback.title'), this.jsToLang('card.snapshots.modal.rollback.confirm'), '', this.jsToLang('card.snapshots.button.rollback'));

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

        async performRollback() {
            this.isAnyRollingBack = true;

            const snapshotIndex = this.snapshots.findIndex(s => s.snapshotId === this.selectedSnapshot.snapshotId);

            if (snapshotIndex !== -1) {
                this.$set(this.snapshots[snapshotIndex], 'isRollingBack', true);
            }

            let isQueued = false;

            try {
                const response = await axios.post(this.xhrUrl + 'rollbackServerSnapshot', {
                    snapshotId: this.selectedSnapshot.snapshotId
                });

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

                        this.activeTasks.activeRollbackSnapshotTask = {
                            snapshotId: this.selectedSnapshot.snapshotId,
                            status: 'pending',
                            taskId: response.data.taskId,
                            progress: 0
                        };

                        this.pollTaskStatus(response.data.taskId, 'rollback', this.selectedSnapshot.snapshotId);
                    } else if (response.data.result === 'success' || response.data.result === 'failed') {
                        await this.refreshList();
                    }
                }
            } catch (error) {
                this.errorNotificationFlash(error.response?.data || 'Failed to rollback snapshot');
            } finally {
                if (!isQueued) {
                    this.isAnyRollingBack = false;

                    if (snapshotIndex !== -1) {
                        this.$set(this.snapshots[snapshotIndex], 'isRollingBack', false);
                    }
                }

                this.selectedSnapshot = null;
            }
        },

        isSnapshotDeleting(snapshotId) {
            const snapshot = this.snapshots.find(s => s.snapshotId === snapshotId);
            if (snapshot?.isDeleting) {
                return true;
            }

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

        isSnapshotRollingBack(snapshotId) {
            const snapshot = this.snapshots.find(s => s.snapshotId === snapshotId);
            if (snapshot?.isRollingBack) {
                return true;
            }

            return this.activeTasks.activeRollbackSnapshotTask?.snapshotId === snapshotId && this.isTaskActive(this.activeTasks.activeRollbackSnapshotTask?.status);
        },

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

    mounted() {
    }
};