/**
 * AnnotationService
 * Coordinates annotation persistence, model association, checked-state updates,
 * and CSV-ready export shaping on top of the repository layer.
 */
class AnnotationService {
    constructor(pool, annotationRepository) {
        this.pool = pool;
        this.annotationRepo = annotationRepository;
    }

    getSelectionLabel(row, valueLanguage = 'cs') {
        if (valueLanguage === 'en') {
            return row.selected_label_en || row.selected_label_cs || '';
        }

        return row.selected_label_cs || row.selected_label_en || '';
    }

    async getExportData(valueLanguage = 'cs') {
        const annotations = await this.annotationRepo.findAllAnnotations();

        return await Promise.all(annotations.map(async (ann) => {
            const selections = await this.annotationRepo.findAnnotationDetail(ann.annotationId);

            const values = {};
            selections.forEach(row => {
                if (row.trait_id) values[row.trait_id] = this.getSelectionLabel(row, valueLanguage);
            });

            return {
                ...ann,
                atlasName: valueLanguage === 'en' ? ann.atlasNameEn : ann.atlasNameCs,
                values
            };
        }));
    }


    async saveAnnotation({ annotationId, atlasId, modelId, fileHash, annotatorName, values, modelFile, mtlFile, textureFile, isChecked, checkerName }) {
        if (!atlasId) throw new Error("Nelze uložit anotaci bez určení atlasu (atlasId).");

        const client = await this.pool.connect();
        try {
            await client.query('BEGIN');
            console.log(`--- START SAVE: atlas=${atlasId}, annotator=${annotatorName}, hash=${fileHash} ---`);

            let dbModelId = null;
            let effectiveHash = fileHash;

            if (!effectiveHash && annotationId) {
                const res = await client.query(
                    'SELECT m.file_hash FROM models m JOIN annotations a ON a.model_id = m.id WHERE a.id = $1::uuid',
                    [annotationId]
                );
                effectiveHash = res.rows[0]?.file_hash;
            }

            if (modelFile || mtlFile || textureFile) {
                dbModelId = await this.annotationRepo.upsertModelInTransaction(client, {
                    modelId,
                    fileHash: effectiveHash,
                    modelPath: modelFile ? `/models/${modelFile.filename}` : null,
                    mtlPath: mtlFile ? `/models/${mtlFile.filename}` : null,
                    texturePath: textureFile ? `/models/${textureFile.filename}` : null
                });
            } else {
                const modelRes = await client.query('SELECT id FROM models WHERE file_hash = $1', [effectiveHash]);
                if (modelRes.rows.length === 0) {
                    console.error(`❌ Model with hash ${effectiveHash} was not found.`);
                    throw new Error("Model nenalezen v databázi.");
                }
                dbModelId = modelRes.rows[0].id;
            }

            let targetAnnotationId = null;

            const dupCheck = await client.query(
                'SELECT id FROM annotations WHERE model_id = $1 AND annotator_name = $2 AND atlas_id = $3::text',
                [dbModelId, annotatorName, atlasId]
            );

            if (dupCheck.rows.length > 0) {
                targetAnnotationId = dupCheck.rows[0].id;
                console.log(`♻️ Updating existing annotation: ${targetAnnotationId}`);
            } else {
                const newAnn = await client.query(
                    'INSERT INTO annotations (model_id, annotator_name, atlas_id) VALUES ($1, $2, $3::text) RETURNING id',
                    [dbModelId, annotatorName, atlasId]
                );
                targetAnnotationId = newAnn.rows[0].id;
                console.log(`✨ Created new annotation: ${targetAnnotationId}`);
            }

            if (typeof isChecked === 'boolean') {
                const normalizedCheckerName = isChecked
                    ? (String(checkerName || '').trim() || null)
                    : null;

                await client.query(
                    'UPDATE annotations SET last_updated = NOW(), atlas_id = $1::text, is_checked = $2, checker_name = $3 WHERE id = $4::uuid',
                    [atlasId, isChecked, normalizedCheckerName, targetAnnotationId]
                );
            } else {
                await client.query(
                    'UPDATE annotations SET last_updated = NOW(), atlas_id = $1::text WHERE id = $2::uuid',
                    [atlasId, targetAnnotationId]
                );
            }
            
            await client.query('DELETE FROM model_trait_selections WHERE annotation_id = $1::uuid', [targetAnnotationId]);

            const valueEntries = Object.entries(values);
            console.log(`📦 Saving ${valueEntries.length} selected trait values.`);

            for (const [traitId, labelValue] of valueEntries) {
                if (labelValue === null || labelValue === undefined || labelValue === "") continue;

                const insertRes = await client.query(`
                    INSERT INTO model_trait_selections (annotation_id, trait_id, option_id)
                    SELECT $1::uuid, $2::text, id FROM trait_options 
                    WHERE trait_id = $2 AND (label_cs = $3 OR label_en = $3)
                    LIMIT 1;
                `, [targetAnnotationId, traitId, labelValue]);

                if (insertRes.rowCount === 0) {
                    console.warn(`⚠️ Value "${labelValue}" for trait "${traitId}" was not found in atlas ${atlasId}.`);
                }
            }

            await client.query('COMMIT');
            console.log(`✅ Save completed for annotation ${targetAnnotationId}`);
            return { annotationId: targetAnnotationId };
        } catch (error) {
            await client.query('ROLLBACK');
            console.error('❌ Annotation service error:', error);
            throw error;
        } finally {
            client.release();
        }
    }

    async getAnnotationDetail(annotationId, valueLanguage = 'cs') {
        const rows = await this.annotationRepo.findAnnotationDetail(annotationId);
        if (!rows || rows.length === 0) return null;

        const values = {};
        rows.forEach(row => {
            if (row.trait_id) values[row.trait_id] = this.getSelectionLabel(row, valueLanguage);
        });

        const first = rows[0];
        return {
            annotationId: first.annotationId,
            atlasId: first.atlasId,
            modelLabel: first.modelId,
            annotator: first.annotator,
            isChecked: first.isChecked,
            checkerName: first.checkerName,
            modelPath: first.modelPath,
            mtlPath: first.mtlPath,
            texturePath: first.texturePath,
            fileHash: first.fileHash,
            lastUpdated: first.lastUpdated,
            values
        };
    }
}

module.exports = AnnotationService;