import { createRequire } from 'module';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import PocketBase from 'pocketbase';

const require = createRequire(import.meta.url);
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

let runtimeConfig = {};
try {
    runtimeConfig = require('../pocket-base/bai_api_pb_hooks/bai_api_shared/config/runtime.js');
} catch (_error) {
    runtimeConfig = {};
}

function readEnvFile(filePath) {
    if (!fs.existsSync(filePath)) return {};

    const content = fs.readFileSync(filePath, 'utf8');
    const result = {};

    for (const rawLine of content.split(/\r?\n/)) {
        const line = rawLine.trim();
        if (!line || line.startsWith('#')) continue;

        const index = line.indexOf('=');
        if (index === -1) continue;

        const key = line.slice(0, index).trim();
        const value = line.slice(index + 1).trim();
        result[key] = value;
    }

    return result;
}

const backendEnv = readEnvFile(path.resolve(__dirname, '..', 'back-end', '.env'));
const PB_URL = String(
    process.env.PB_URL
    || backendEnv.POCKETBASE_API_URL
    || runtimeConfig.POCKETBASE_API_URL
    || 'http://127.0.0.1:8090'
).replace(/\/+$/, '');
const AUTH_TOKEN = process.env.POCKETBASE_AUTH_TOKEN || runtimeConfig.POCKETBASE_AUTH_TOKEN || '';
const SOFT_DELETE_RULE = 'is_delete = 0';

if (!AUTH_TOKEN) {
    console.error('❌ 缺少 POCKETBASE_AUTH_TOKEN，无法执行软删除规则迁移。');
    process.exit(1);
}

const pb = new PocketBase(PB_URL);

function isSystemCollection(collection) {
    return !!(collection && (collection.system || String(collection.name || '').startsWith('_')));
}

function normalizeFieldPayload(field) {
    const payload = Object.assign({}, field);

    if (field.type === 'number') {
        if (Object.prototype.hasOwnProperty.call(field, 'default')) payload.default = field.default;
        if (Object.prototype.hasOwnProperty.call(field, 'min')) payload.min = field.min;
        if (Object.prototype.hasOwnProperty.call(field, 'max')) payload.max = field.max;
        if (Object.prototype.hasOwnProperty.call(field, 'onlyInt')) payload.onlyInt = !!field.onlyInt;
    }

    if (field.type === 'autodate') {
        payload.onCreate = typeof field.onCreate === 'boolean' ? field.onCreate : true;
        payload.onUpdate = typeof field.onUpdate === 'boolean' ? field.onUpdate : false;
    }

    if (field.type === 'file') {
        payload.maxSelect = typeof field.maxSelect === 'number' ? field.maxSelect : 0;
        payload.maxSize = typeof field.maxSize === 'number' ? field.maxSize : 0;
        payload.mimeTypes = Array.isArray(field.mimeTypes) ? field.mimeTypes : null;
    }

    return payload;
}

function mergeRuleWithSoftDelete(rule) {
    const currentRule = typeof rule === 'string' ? rule.trim() : '';

    if (!currentRule) return SOFT_DELETE_RULE;
    if (currentRule === SOFT_DELETE_RULE) return currentRule;
    if (currentRule.includes(SOFT_DELETE_RULE)) return currentRule;

    return `(${currentRule}) && ${SOFT_DELETE_RULE}`;
}

function buildCollectionPayload(collection) {
    return {
        name: collection.name,
        type: collection.type,
        listRule: mergeRuleWithSoftDelete(collection.listRule),
        viewRule: mergeRuleWithSoftDelete(collection.viewRule),
        createRule: collection.createRule,
        updateRule: collection.updateRule,
        deleteRule: collection.deleteRule,
        fields: (collection.fields || []).filter((field) => field && field.name !== 'id').map((field) => normalizeFieldPayload(field)),
        indexes: collection.indexes || [],
    };
}

async function applyRules() {
    const collections = await pb.collections.getFullList({ sort: 'name' });
    const changed = [];

    for (const collection of collections) {
        if (isSystemCollection(collection)) continue;

        const hasSoftDelete = (collection.fields || []).some((field) => field && field.name === 'is_delete');
        if (!hasSoftDelete) continue;

        const nextListRule = mergeRuleWithSoftDelete(collection.listRule);
        const nextViewRule = mergeRuleWithSoftDelete(collection.viewRule);
        const listChanged = nextListRule !== (collection.listRule || '');
        const viewChanged = nextViewRule !== (collection.viewRule || '');

        if (!listChanged && !viewChanged) {
            changed.push({ name: collection.name, action: 'skipped', listRule: nextListRule, viewRule: nextViewRule });
            continue;
        }

        await pb.collections.update(collection.id, buildCollectionPayload(collection));
        changed.push({ name: collection.name, action: 'updated', listRule: nextListRule, viewRule: nextViewRule });
    }

    return changed;
}

async function verifyRules() {
    const collections = await pb.collections.getFullList({ sort: 'name' });
    const failed = [];

    for (const collection of collections) {
        if (isSystemCollection(collection)) continue;
        const hasSoftDelete = (collection.fields || []).some((field) => field && field.name === 'is_delete');
        if (!hasSoftDelete) continue;

        const listRule = String(collection.listRule || '');
        const viewRule = String(collection.viewRule || '');

        if (!listRule.includes(SOFT_DELETE_RULE) || !viewRule.includes(SOFT_DELETE_RULE)) {
            failed.push({ name: collection.name, listRule, viewRule });
        }
    }

    if (failed.length) {
        throw new Error(`以下集合未正确应用软删除规则: ${JSON.stringify(failed, null, 2)}`);
    }
}

async function main() {
    try {
        console.log(`🔄 正在连接 PocketBase: ${PB_URL}`);
        pb.authStore.save(AUTH_TOKEN, null);
        console.log('✅ 已使用 POCKETBASE_AUTH_TOKEN 载入认证状态。');

        const changed = await applyRules();
        console.log('📝 规则更新结果：');
        console.log(JSON.stringify(changed, null, 2));

        await verifyRules();
        console.log('✅ 校验通过：所有带 is_delete 的业务集合已默认过滤 is_delete = 0。');
        console.log('🎉 软删除默认查询规则迁移完成！');
    } catch (error) {
        console.error('❌ 软删除默认查询规则迁移失败:', error.response?.data || error.message || error);
        process.exitCode = 1;
    }
}

main();