"use strict";

const sql = require('../../services/sql');
const optionService = require('../../services/options');
const treeService = require('../../services/tree');

function getNotesAndBranchesAndAttributes(noteIds) {
    noteIds = Array.from(new Set(noteIds));
    const notes = treeService.getNotes(noteIds);

    noteIds = notes.map(note => note.noteId);

    // joining child note to filter out not completely synchronised notes which would then cause errors later
    // cannot do that with parent because of root note's 'none' parent
    const branches = sql.getManyRows(` 
        SELECT 
            branches.branchId,
            branches.noteId,
            branches.parentNoteId,
            branches.notePosition,
            branches.prefix,
            branches.isExpanded
        FROM branches
        JOIN notes AS child ON child.noteId = branches.noteId
        WHERE branches.isDeleted = 0
          AND (branches.noteId IN (???) OR parentNoteId IN (???))`, noteIds);

    // sorting in memory is faster
    branches.sort((a, b) => a.notePosition - b.notePosition < 0 ? -1 : 1);

    const attributes = sql.getManyRows(`
        SELECT
            attributeId,
            noteId,
            type,
            name,
            value,
            position,
            isInheritable
        FROM attributes
        WHERE isDeleted = 0 
          AND (noteId IN (???) OR (type = 'relation' AND value IN (???)))`, noteIds);

    // sorting in memory is faster
    attributes.sort((a, b) => a.position - b.position < 0 ? -1 : 1);

    return {
        branches,
        notes,
        attributes
    };
}

function getTree(req) {
    const subTreeNoteId = req.query.subTreeNoteId || optionService.getOption('hoistedNoteId');

    const noteIds = sql.getColumn(`
        WITH RECURSIVE
            treeWithDescendants(noteId, isExpanded) AS (
                SELECT noteId, 1 FROM branches WHERE parentNoteId = ? AND isDeleted = 0
                UNION
                SELECT branches.noteId, branches.isExpanded FROM branches
                  JOIN treeWithDescendants ON branches.parentNoteId = treeWithDescendants.noteId
                WHERE treeWithDescendants.isExpanded = 1 
                  AND branches.isDeleted = 0
            ),
            treeWithDescendantsAndAscendants AS (
                SELECT noteId FROM treeWithDescendants
                UNION
                SELECT branches.parentNoteId FROM branches
                  JOIN treeWithDescendantsAndAscendants ON branches.noteId = treeWithDescendantsAndAscendants.noteId
                WHERE branches.isDeleted = 0
                  AND branches.parentNoteId != ?
            ),
            treeWithDescendantsAscendantsAndTemplates AS (
                SELECT noteId FROM treeWithDescendantsAndAscendants
                UNION
                SELECT attributes.value FROM attributes
                   JOIN treeWithDescendantsAscendantsAndTemplates ON attributes.noteId = treeWithDescendantsAscendantsAndTemplates.noteId
                WHERE attributes.isDeleted = 0
                    AND attributes.type = 'relation'
                    AND attributes.name = 'template'
            )
        SELECT noteId FROM treeWithDescendantsAscendantsAndTemplates`, [subTreeNoteId, subTreeNoteId]);

    noteIds.push(subTreeNoteId);

    return getNotesAndBranchesAndAttributes(noteIds);
}

function load(req) {
    return getNotesAndBranchesAndAttributes(req.body.noteIds);
}

module.exports = {
    getTree,
    load
};
