/**
 * Atlas Import Utilities
 * Shared helpers for reading atlas JSON, merging translation sidecars, validating
 * atlas structure, and converting image or trait identifiers during imports.
 */
const fs = require('fs');
const path = require('path');

const ATLAS_TRANSLATION_SUFFIX = '.translations.cs.json';

function readJsonFile(filePath) {
    const fileContents = fs.readFileSync(filePath, 'utf8').replace(/^\uFEFF/, '');
    return JSON.parse(fileContents);
}

function normalizeText(value) {
    if (typeof value === 'string') {
        return value;
    }

    if (value === undefined || value === null) {
        return '';
    }

    return String(value);
}

function requireText(value, fieldPath, fileLabel) {
    if (typeof value !== 'string') {
        throw new Error(`${fileLabel} is missing required string field: ${fieldPath}`);
    }

    return value;
}

function requireArray(value, fieldPath, fileLabel) {
    if (!Array.isArray(value)) {
        throw new Error(`${fileLabel} is missing required array field: ${fieldPath}`);
    }

    return value;
}

function getAtlasTranslationFilePath(filePath) {
    const extension = path.extname(filePath);
    const withoutExtension = filePath.slice(0, -extension.length);
    return `${withoutExtension}${ATLAS_TRANSLATION_SUFFIX}`;
}

function getSectionTraits(section) {
    return section?.traits || section?.znaky || [];
}

function isLegacyLocalizedAtlas(atlas) {
    return Boolean(atlas && (atlas.label_cs || atlas.label_en || atlas.popis_cs || atlas.popis_en));
}

function mergeTranslatedAtlas(atlasSource, atlasTranslations, filePath) {
    const fileLabel = path.basename(filePath);

    if (!atlasSource?.id) {
        throw new Error(`${fileLabel} is missing required field: id`);
    }

    if (atlasTranslations?.id && atlasTranslations.id !== atlasSource.id) {
        throw new Error(
            `${fileLabel} translation id mismatch: expected ${atlasSource.id}, received ${atlasTranslations.id}`
        );
    }

    const sourceSections = requireArray(atlasSource.sections || [], 'sections', fileLabel);
    const translatedSections = requireArray(atlasTranslations.sections || [], 'sections', `${fileLabel}${ATLAS_TRANSLATION_SUFFIX}`);

    if (sourceSections.length !== translatedSections.length) {
        throw new Error(
            `${fileLabel} translation section count mismatch: expected ${sourceSections.length}, received ${translatedSections.length}`
        );
    }

    return {
        id: atlasSource.id,
        label_cs: requireText(atlasTranslations.label, 'label', `${fileLabel}${ATLAS_TRANSLATION_SUFFIX}`),
        label_en: requireText(atlasSource.label, 'label', fileLabel),
        popis_cs: normalizeText(atlasTranslations.description),
        popis_en: normalizeText(atlasSource.description),
        sections: sourceSections.map((section, sectionIndex) => {
            const translatedSection = translatedSections[sectionIndex];
            const sourceTraits = requireArray(getSectionTraits(section), `sections[${sectionIndex}].traits`, fileLabel);
            const translatedTraits = requireArray(
                getSectionTraits(translatedSection),
                `sections[${sectionIndex}].traits`,
                `${fileLabel}${ATLAS_TRANSLATION_SUFFIX}`
            );

            if (sourceTraits.length !== translatedTraits.length) {
                throw new Error(
                    `${fileLabel} translation trait count mismatch in section ${sectionIndex}: expected ${sourceTraits.length}, received ${translatedTraits.length}`
                );
            }

            return {
                nazev_cs: requireText(translatedSection.name, `sections[${sectionIndex}].name`, `${fileLabel}${ATLAS_TRANSLATION_SUFFIX}`),
                nazev_en: requireText(section.name, `sections[${sectionIndex}].name`, fileLabel),
                znaky: sourceTraits.map((trait, traitIndex) => {
                    const translatedTrait = translatedTraits[traitIndex];
                    const sourceOptions = requireArray(trait.options || [], `sections[${sectionIndex}].traits[${traitIndex}].options`, fileLabel);
                    const translatedOptions = requireArray(
                        translatedTrait.options || [],
                        `sections[${sectionIndex}].traits[${traitIndex}].options`,
                        `${fileLabel}${ATLAS_TRANSLATION_SUFFIX}`
                    );

                    if (!trait?.id) {
                        throw new Error(`${fileLabel} is missing trait id at sections[${sectionIndex}].traits[${traitIndex}]`);
                    }

                    if (translatedTrait?.id && translatedTrait.id !== trait.id) {
                        throw new Error(
                            `${fileLabel} translation trait id mismatch at sections[${sectionIndex}].traits[${traitIndex}]: expected ${trait.id}, received ${translatedTrait.id}`
                        );
                    }

                    if (sourceOptions.length !== translatedOptions.length) {
                        throw new Error(
                            `${fileLabel} translation option count mismatch for trait ${trait.id}: expected ${sourceOptions.length}, received ${translatedOptions.length}`
                        );
                    }

                    return {
                        id: trait.id,
                        label_cs: requireText(
                            translatedTrait.label,
                            `sections[${sectionIndex}].traits[${traitIndex}].label`,
                            `${fileLabel}${ATLAS_TRANSLATION_SUFFIX}`
                        ),
                        label_en: requireText(trait.label, `sections[${sectionIndex}].traits[${traitIndex}].label`, fileLabel),
                        popis_cs: normalizeText(translatedTrait.description),
                        popis_en: normalizeText(trait.description),
                        options: sourceOptions.map((option, optionIndex) => ({
                            label_cs: requireText(
                                translatedOptions[optionIndex]?.label,
                                `sections[${sectionIndex}].traits[${traitIndex}].options[${optionIndex}].label`,
                                `${fileLabel}${ATLAS_TRANSLATION_SUFFIX}`
                            ),
                            label_en: requireText(
                                option.label,
                                `sections[${sectionIndex}].traits[${traitIndex}].options[${optionIndex}].label`,
                                fileLabel
                            ),
                            images: Array.isArray(option.images) ? option.images : [],
                        })),
                    };
                }),
            };
        }),
    };
}

function readAtlasJson(filePath) {
    const atlasSource = readJsonFile(filePath);

    if (isLegacyLocalizedAtlas(atlasSource)) {
        return atlasSource;
    }

    const translationFilePath = getAtlasTranslationFilePath(filePath);
    if (!fs.existsSync(translationFilePath)) {
        throw new Error(`Atlas translation file not found: ${path.basename(translationFilePath)}`);
    }

    const atlasTranslations = readJsonFile(translationFilePath);
    return mergeTranslatedAtlas(atlasSource, atlasTranslations, filePath);
}

function partitionOptionImages(images, resolveAtlasImage) {
    const resolvedImages = (images || []).map(imageReference => resolveAtlasImage(imageReference));
    return {
        photos: resolvedImages.filter(imagePath => !imagePath.includes('/paintings/')),
        drawings: resolvedImages.filter(imagePath => imagePath.includes('/paintings/')),
    };
}

function toImportedTraitId(atlasId, traitId) {
    const atlasScopedPrefix = `${atlasId}::`;
    if (traitId.startsWith(atlasScopedPrefix)) {
        return traitId;
    }

    return `${atlasScopedPrefix}${traitId}`;
}

module.exports = {
    ATLAS_TRANSLATION_SUFFIX,
    getAtlasTranslationFilePath,
    mergeTranslatedAtlas,
    partitionOptionImages,
    readAtlasJson,
    toImportedTraitId,
};