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

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 = (process.env.PB_URL || backendEnv.POCKETBASE_API_URL || 'https://bai-api.blv-oa.com/pb').replace(/\/+$/, '');
const AUTH_TOKEN = process.env.POCKETBASE_AUTH_TOKEN || runtimeConfig.POCKETBASE_AUTH_TOKEN || '';
const DRY_RUN = String(process.env.DRY_RUN || '').trim() === '1';

if (!AUTH_TOKEN) {
    console.error('❌ 缺少认证信息，请提供 POCKETBASE_AUTH_TOKEN。');
    process.exit(1);
}

function getUrlCandidates(url) {
    const trimmed = String(url || '').replace(/\/+$/, '');
    const candidates = [];
    if (trimmed) {
        candidates.push(trimmed);
    }

    const withoutPb = trimmed.replace(/\/pb$/i, '');
    if (withoutPb && candidates.indexOf(withoutPb) === -1) {
        candidates.push(withoutPb);
    }

    return candidates;
}

function normalizeText(value) {
    return String(value || '').trim();
}

function toParameterArray(value) {
    if (value === null || typeof value === 'undefined' || value === '') {
        return [];
    }

    let source = value;
    if (typeof source === 'string') {
        try {
            source = JSON.parse(source);
        } catch (_error) {
            const raw = normalizeText(source);
            if (raw.indexOf('map[') === 0 && raw.endsWith(']')) {
                const mapped = {};
                const body = raw.slice(4, -1).trim();
                const pairs = body ? body.split(/\s+/) : [];
                for (let i = 0; i < pairs.length; i += 1) {
                    const pair = pairs[i];
                    const separatorIndex = pair.indexOf(':');
                    if (separatorIndex <= 0) continue;
                    const key = normalizeText(pair.slice(0, separatorIndex));
                    if (!key) continue;
                    mapped[key] = pair.slice(separatorIndex + 1);
                }
                source = mapped;
            } else {
                return [];
            }
        }
    }

    const rows = [];
    const indexByName = {};

    function upsert(nameValue, rawValue) {
        const name = normalizeText(nameValue);
        if (!name) return;

        const valueText = rawValue === null || typeof rawValue === 'undefined' ? '' : String(rawValue);
        const existingIndex = indexByName[name];
        if (typeof existingIndex === 'number') {
            rows[existingIndex].value = valueText;
            return;
        }

        indexByName[name] = rows.length;
        rows.push({ name, value: valueText });
    }

    if (Array.isArray(source)) {
        for (let i = 0; i < source.length; i += 1) {
            const item = source[i] && typeof source[i] === 'object' ? source[i] : null;
            if (!item) continue;
            upsert(item.name || item.key, item.value);
        }
        return rows;
    }

    if (typeof source !== 'object') {
        return [];
    }

    try {
        source = JSON.parse(JSON.stringify(source));
    } catch (_error) {}

    const keys = Object.keys(source || {});
    for (let i = 0; i < keys.length; i += 1) {
        upsert(keys[i], source[keys[i]]);
    }

    return rows;
}

function isSameArray(left, right) {
    return JSON.stringify(left || []) === JSON.stringify(right || []);
}

async function requestPbJson(baseUrl, method, apiPath, token, body) {
    const res = await fetch(baseUrl + apiPath, {
        method: method,
        headers: Object.assign(
            {
                Authorization: `Bearer ${token}`,
            },
            body ? { 'Content-Type': 'application/json' } : {},
        ),
        body: body ? JSON.stringify(body) : undefined,
    });

    const text = await res.text();
    let json = {};
    try {
        json = text ? JSON.parse(text) : {};
    } catch (_error) {
        json = { raw: text };
    }

    if (!res.ok) {
        const err = new Error(json.message || `HTTP ${res.status}`);
        err.status = res.status;
        err.response = json;
        throw err;
    }

    return json;
}

async function migrate() {
    try {
        const urlCandidates = getUrlCandidates(PB_URL);
        let activeUrl = '';
        let lastError = null;

        for (let i = 0; i < urlCandidates.length; i += 1) {
            const candidate = urlCandidates[i];
            try {
                await requestPbJson(
                    candidate,
                    'GET',
                    '/api/collections/tbl_product_list/records?page=1&perPage=1',
                    AUTH_TOKEN,
                );
                activeUrl = candidate;
                console.log(`✅ 已加载 POCKETBASE_AUTH_TOKEN（${candidate}）。`);
                break;
            } catch (error) {
                lastError = error;
                console.log(`⚠️ 候选地址探测失败（${candidate}）:`, {
                    status: error && error.status,
                    message: error && error.message,
                });
            }
        }

        if (!activeUrl) {
            throw lastError || new Error('无法连接 PocketBase 或认证失败');
        }

        console.log(`🔄 开始迁移 tbl_product_list.prod_list_parameters，PB: ${activeUrl}`);
        if (DRY_RUN) {
            console.log('🧪 当前为 DRY_RUN=1，仅预览不会写入数据库。');
        }

        let page = 1;
        const perPage = 200;
        let total = 0;
        let changed = 0;
        let skipped = 0;
        let failed = 0;

        while (true) {
            const list = await requestPbJson(
                activeUrl,
                'GET',
                `/api/collections/tbl_product_list/records?page=${page}&perPage=${perPage}`,
                AUTH_TOKEN,
            );

            const items = Array.isArray(list.items) ? list.items : [];
            if (!items.length) {
                break;
            }

            for (let i = 0; i < items.length; i += 1) {
                const item = items[i];
                total += 1;

                try {
                    const current = item.prod_list_parameters;
                    const normalized = toParameterArray(current);

                    if (isSameArray(current, normalized)) {
                        skipped += 1;
                        continue;
                    }

                    if (!DRY_RUN) {
                        await requestPbJson(
                            activeUrl,
                            'PATCH',
                            `/api/collections/tbl_product_list/records/${item.id}`,
                            AUTH_TOKEN,
                            { prod_list_parameters: normalized },
                        );
                    }

                    changed += 1;
                    console.log(`✅ 已迁移: ${item.prod_list_id || item.id}`);
                } catch (error) {
                    failed += 1;
                    console.error(`❌ 迁移失败: ${item.prod_list_id || item.id}`, error.message || error);
                }
            }

            const totalPages = Number(list.totalPages || 1);
            if (page >= totalPages) {
                break;
            }
            page += 1;
        }

        console.log('\n🎯 迁移完成');
        console.log(`- 总记录: ${total}`);
        console.log(`- 已变更: ${changed}`);
        console.log(`- 跳过不变: ${skipped}`);
        console.log(`- 失败: ${failed}`);
    } catch (error) {
        console.error('❌ 迁移任务执行失败:', {
            status: error && error.status,
            message: error && error.message,
            response: error && error.response,
        });
        process.exitCode = 1;
    }
}

migrate();
