<template>
    <DialogPro v-model="visible" :title="$t('commons.button.import')" size="large">
        <div>
            <el-alert :closable="false" show-icon type="info">
                <template #default>
                    <div>{{ $t('commons.msg.importHelper') }}</div>
                </template>
            </el-alert>
            <el-upload
                action="#"
                :auto-upload="false"
                ref="uploadRef"
                class="float-left mt-2"
                :show-file-list="false"
                :limit="1"
                accept=".json"
                :on-change="fileOnChange"
                :on-exceed="handleExceed"
                v-model:file-list="uploaderFiles"
            >
                <el-button class="float-left" type="primary">{{ $t('commons.button.upload') }}</el-button>
            </el-upload>

            <el-card class="mt-2 w-full" v-loading="loading">
                <ComplexTable
                    :pagination-config="paginationConfig"
                    @search="search"
                    v-model:selects="selects"
                    :data="pageData"
                    :height="440"
                >
                    <el-table-column type="selection" fix />
                    <el-table-column :label="$t('commons.table.status')" :min-width="80">
                        <template #default="{ row }">
                            <Status :status="row.status" />
                        </template>
                    </el-table-column>
                    <el-table-column :label="$t('firewall.address')" :min-width="100">
                        <template #default="{ row }">
                            <span v-if="row.address && row.address !== 'Anywhere'">{{ row.address }}</span>
                            <span v-else>{{ $t('firewall.allIP') }}</span>
                        </template>
                    </el-table-column>
                    <el-table-column :label="$t('firewall.strategy')" :min-width="80" prop="strategy">
                        <template #default="{ row }">
                            {{ row.strategy === 'accept' ? $t('firewall.allow') : $t('firewall.deny') }}
                        </template>
                    </el-table-column>
                    <el-table-column
                        :label="$t('commons.table.description')"
                        :min-width="120"
                        prop="description"
                        show-overflow-tooltip
                    />
                </ComplexTable>
            </el-card>
        </div>
        <template #footer>
            <span class="dialog-footer">
                <el-button @click="visible = false">
                    {{ $t('commons.button.cancel') }}
                </el-button>
                <el-button type="primary" plain :disabled="displayData.length === 0" @click="onImportAll">
                    {{ $t('commons.button.importAll') }}
                </el-button>
                <el-button type="primary" :disabled="selects.length === 0" @click="() => onImport()">
                    {{ $t('commons.button.import') }}
                </el-button>
            </span>
        </template>
    </DialogPro>
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import { genFileId, UploadFile, UploadFiles, UploadProps, UploadRawFile } from 'element-plus';
import { MsgError, MsgSuccess } from '@/utils/message';
import i18n from '@/lang';
import { operateIPRule, searchFireRule } from '@/api/modules/host';
import { Host } from '@/api/interface/host';

const emit = defineEmits<{ (e: 'search'): void }>();

const visible = ref(false);
const loading = ref(false);
const selects = ref<any>([]);
const displayData = ref<any>([]);
const currentRules = ref<Host.RuleInfo[]>([]);

const uploadRef = ref();
const uploaderFiles = ref<UploadFiles>([]);
const pageData = ref([]);
const paginationConfig = reactive({
    currentPage: 1,
    pageSize: 10,
    total: 0,
});

const acceptParams = async (): Promise<void> => {
    resetImportData();
    visible.value = true;

    loadCurrentData();
};

const resetImportData = () => {
    loading.value = false;
    displayData.value = [];
    pageData.value = [];
    selects.value = [];
    uploaderFiles.value = [];
    paginationConfig.currentPage = 1;
    paginationConfig.total = 0;
    uploadRef.value?.clearFiles();
};

const loadCurrentData = async () => {
    const res = await searchFireRule({
        type: 'address',
        strategy: '',
        info: '',
        page: 1,
        pageSize: 10000,
    });
    currentRules.value = res.data.items || [];
};

const search = () => {
    const startIndex = (paginationConfig.currentPage - 1) * paginationConfig.pageSize;
    const endIndex = startIndex + paginationConfig.pageSize;
    pageData.value = displayData.value.slice(startIndex, endIndex);
};

const fileOnChange = (_uploadFile: UploadFile, uploadFiles: UploadFiles) => {
    loading.value = true;
    displayData.value = [];
    uploaderFiles.value = uploadFiles;

    const reader = new FileReader();
    reader.onload = (e) => {
        try {
            const content = e.target.result as string;
            const parsed = JSON.parse(content);

            if (!Array.isArray(parsed)) {
                MsgError(i18n.global.t('commons.msg.errImportFormat'));
                loading.value = false;
                return;
            }

            for (const item of parsed) {
                if (!checkDataFormat(item)) {
                    MsgError(i18n.global.t('commons.msg.errImportFormat'));
                    loading.value = false;
                    return;
                }
            }

            compareRules(parsed);
            loading.value = false;
        } catch (error) {
            MsgError(i18n.global.t('commons.msg.errImport') + error.message);
            loading.value = false;
        }
    };
    reader.readAsText(_uploadFile.raw);
};

const handleExceed: UploadProps['onExceed'] = (files) => {
    uploadRef.value!.clearFiles();
    const file = files[0] as UploadRawFile;
    file.uid = genFileId();
    uploadRef.value!.handleStart(file);
};

const checkDataFormat = (item: any): boolean => {
    if (!item.address || !item.strategy) {
        return false;
    }
    if (!['accept', 'drop'].includes(item.strategy)) {
        return false;
    }
    return true;
};

const compareRules = (importedRules: any[]) => {
    const newRules: any[] = [];
    const conflictRules: any[] = [];
    const duplicateRules: any[] = [];

    for (const importedRule of importedRules) {
        const key = `${importedRule.address || 'Anywhere'}`;

        const existingRule = currentRules.value.find((rule) => {
            const existingKey = `${rule.address || 'Anywhere'}`;
            return existingKey === key;
        });

        if (!existingRule) {
            newRules.push({ ...importedRule, status: 'new' });
        } else if (existingRule.strategy !== importedRule.strategy) {
            conflictRules.push({
                ...importedRule,
                status: 'conflict',
                existingStrategy: existingRule.strategy,
            });
        } else {
            duplicateRules.push({ ...importedRule, status: 'duplicate' });
        }
    }

    displayData.value = [...newRules, ...conflictRules, ...duplicateRules];
    paginationConfig.total = displayData.value.length;
    search();
};

const onImportAll = async () => {
    await onImport(displayData.value);
};

const onImport = async (rules = selects.value) => {
    loading.value = true;
    let successCount = 0;
    let errorCount = 0;

    for (const rule of rules) {
        try {
            const params: Host.RuleIP = {
                operation: 'add',
                address: rule.address || 'Anywhere',
                strategy: rule.strategy,
                description: rule.description || '',
            };

            await operateIPRule(params);
            successCount++;
        } catch (error) {
            errorCount++;
            console.error('Failed to import rule:', rule, error);
        }
    }

    loading.value = false;

    if (errorCount === 0) {
        MsgSuccess(i18n.global.t('firewall.importSuccess', [successCount]));
        visible.value = false;
        emit('search');
    } else {
        MsgError(i18n.global.t('firewall.importPartialSuccess', [successCount, errorCount]));
        emit('search');
    }
};

defineExpose({
    acceptParams,
});
</script>
