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 || '';

if (!AUTH_TOKEN) {
    console.error('❌ 缺少 POCKETBASE_AUTH_TOKEN，无法执行 is_delete 字段迁移。');
    process.exit(1);
}

const pb = new PocketBase(PB_URL);
const TARGET_FIELD = {
    name: 'is_delete',
    type: 'number',
    required: false,
    presentable: true,
    hidden: false,
    default: 0,
    min: 0,
    max: 1,
    onlyInt: true,
};

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

function normalizeFieldPayload(field, targetSpec) {
    const payload = field ? Object.assign({}, field) : {};
    const next = targetSpec || field || {};

    if (field && field.id) {
        payload.id = field.id;
    }

    payload.name = next.name;
    payload.type = next.type;

    if (typeof next.required !== 'undefined') {
        payload.required = !!next.required;
    }
    if (typeof next.presentable !== 'undefined') {
        payload.presentable = !!next.presentable;
    }
    if (typeof next.hidden !== 'undefined') {
        payload.hidden = !!next.hidden;
    }

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

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

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

    return payload;
}

function buildCollectionPayload(collection, fields) {
    return {
        name: collection.name,
        type: collection.type,
        listRule: collection.listRule,
        viewRule: collection.viewRule,
        createRule: collection.createRule,
        updateRule: collection.updateRule,
        deleteRule: collection.deleteRule,
        fields,
        indexes: collection.indexes || [],
    };
}

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

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

        const currentFields = Array.isArray(collection.fields) ? collection.fields : [];
        const existingField = currentFields.find((field) => field && field.name === TARGET_FIELD.name);
        const nextFields = currentFields
            .filter((field) => field && field.name !== 'id')
            .map((field) => normalizeFieldPayload(field));

        if (existingField) {
            for (let i = 0; i < nextFields.length; i += 1) {
                if (nextFields[i].name === TARGET_FIELD.name) {
                    nextFields[i] = normalizeFieldPayload(existingField, TARGET_FIELD);
                    break;
                }
            }
        } else {
            nextFields.push(normalizeFieldPayload(null, TARGET_FIELD));
        }

        await pb.collections.update(collection.id, buildCollectionPayload(collection, nextFields));
        changed.push({ name: collection.name, action: existingField ? 'normalized' : 'added' });
    }

    return changed;
}

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

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

        let page = 1;
        let patched = 0;
        const perPage = 200;

        while (true) {
            const list = await pb.collection(collection.name).getList(page, perPage, {
                fields: 'id,is_delete',
                skipTotal: false,
            });

            const items = Array.isArray(list.items) ? list.items : [];
            for (const item of items) {
                const value = item && Object.prototype.hasOwnProperty.call(item, 'is_delete') ? item.is_delete : null;
                if (value === 0 || value === '0') continue;

                await pb.collection(collection.name).update(item.id, { is_delete: 0 });
                patched += 1;
            }

            if (page >= list.totalPages) break;
            page += 1;
        }

        summary.push({ name: collection.name, backfilledRecords: patched });
    }

    return summary;
}

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

    for (const collection of collections) {
        if (isSystemCollection(collection)) continue;
        const field = (collection.fields || []).find((item) => item && item.name === TARGET_FIELD.name);
        if (!field || field.type !== 'number') failed.push(collection.name);
    }

    if (failed.length) {
        throw new Error('以下集合缺少 is_delete 字段或类型不正确: ' + failed.join(', '));
    }
}

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

        const changed = await addFieldToCollections();
        console.log('📝 已更新集合：');
        console.log(JSON.stringify(changed, null, 2));

        const backfilled = await backfillRecords();
        console.log('📝 已回填记录：');
        console.log(JSON.stringify(backfilled, null, 2));

        await verifyCollections();
        console.log('✅ 校验通过：所有业务集合已包含 is_delete(number, default=0) 字段。');
        console.log('🎉 is_delete 字段迁移完成！');
    } catch (error) {
        console.error('❌ is_delete 字段迁移失败:', error.response?.data || error.message || error);
        process.exitCode = 1;
    }
}

main();
