/* eslint-disable no-restricted-syntax */

const hash = require('pbkdf2-password')()

const { getDB } = require('../../../utils/mongo')
// eslint-disable-next-line import/order
const ObjectId = require('mongodb').ObjectID

let db = null

const connect = async () => {
    db = await getDB('task-boss')
}

const _idToId = (data) => {
    const { _id, ...rest } = data

    return {
        id: _id,
        ...rest,
    }
}

const DEPTS_COLLECTION = 'depts4'
const PEOPLES_COLLECTION = 'peoples4'
const USERS_COLL = 'users3'

const getDepts = async () => {
    if (db === null) throw new Error('no db connection')

    const deptsCollection = db.collection(DEPTS_COLLECTION)

    let responseData = null

    try {
        responseData = await deptsCollection.aggregate([{
            $lookup: {
                from: 'peoples',
                let: {
                    id_fio_resp: '$idFio',
                },
                pipeline: [
                    {
                        $match:
                        {
                            $expr:
                            {
                                $eq: ['$id', '$$id_fio_resp'],
                            },
                        },
                    },
                    {
                        $project: {
                            id: '$_id',
                            _id: 0,
                            family: 1,
                            name: 1,
                            secondName: 1,
                            email: 1,
                            phone: 1,
                        },
                    }],
                as: 'responsible',
            },
        },
        {
            $unwind: '$responsible',
        },
        {
            $project: {
                id: '$_id',
                _id: 0,
                parentId: '$parentDept',
                name: 1,
                qty: {
                    $size: '$employees',
                },
                responsible: '$responsible',
                notes: '$note',
                tasks: {
                    inWork: '0',
                    newTasks: '0',
                },
            },
        },
        ]).toArray()
    } catch (e) {
        console.log(e.message)
    }

    if (!responseData || responseData?.length === 0) {
        responseData = require('./stubs/depts.json').body
    }

    return responseData
}

const getDeptData = async (deptId) => {
    if (db === null) throw new Error('no db connection')

    const deptsCollection = db.collection(DEPTS_COLLECTION)
    const data = await deptsCollection.aggregate([
        {
            $match: {
                _id: new ObjectId(deptId),
            },
        },
        {
            $lookup: {
                from: 'peoples',
                pipeline: [{
                    $project: {
                        id: '$_id',
                        _id: 0,
                        family: 1,
                        name: 1,
                        secondName: 1,
                        email: 1,
                        phone: 1,
                    },
                }],
                localField: 'idFio',
                foreignField: 'id',
                as: 'responsible',
            },
        },
        {
            $unwind: '$responsible',
        },
        {
            $project: {
                id: '$_id',
                _id: 0,
                parentId: '$parentDept',
                name: 1,
                qty: {
                    $size: '$employees',
                },
                responsible: '$responsible',
                notes: '$note',
                tasks: {
                    inWork: '0',
                    newTasks: '0',
                },
            },
        },
    ]).toArray()

    if (data.length === 0) {
        throw new Error('No data')
    }

    return _idToId(data[0])
}

const dropDocuments = async (id) => {
    try {
        const deptsCollection = db.collection(DEPTS_COLLECTION)

        const data = await deptsCollection.find({
            parentDept: id,
        }).toArray()

        data.forEach((element) => {
            dropDocuments(element._id)
        })

        deptsCollection.deleteOne({
            _id: new ObjectId(id),
        })
    } catch (e) {
        console.log(e)
    }
}

const deleteDeptById = async (body) => {
    if (db === null) throw new Error('no db connection');
    try {
        // eslint-disable-next-line guard-for-in
        for (let deptId in body) {
            dropDocuments(deptId)
        }
    } catch (e) {
        console.log(e)
    }
}

const getPeoplesData = async () => {
    if (db === null) throw new Error('no db connection')

    const peoplesCollection = db.collection(PEOPLES_COLLECTION)
    const data = await peoplesCollection.find().toArray()

    if (data.length === 0) {
        const newData = require('./stubs/peoples/success.json').data

        peoplesCollection.insertMany(newData)

        return _idToId(newData)
    }

    return data
}

const createDept = async ({ form, peoples }) => {
    if (db === null) throw new Error('no db connection')

    const deptsCollection = db.collection(DEPTS_COLLECTION)

    const data = await deptsCollection.find({
        name: form.name,
    }).toArray()

    if (data.length > 0) throw new Error('duplication of stirng')

    const employees = []
    peoples.forEach((item) => employees.push({
        id: item.id,
    }))
    const dataToInsert = {
        ...form, employees,
    }
    deptsCollection.insertMany([dataToInsert])

    return dataToInsert
}
const authenticate = async (login, pass, fn) => {
    if (db === null) return fn(new Error('no db connection'))
    const usersCollection = db.collection(USERS_COLL)
    const users = await usersCollection.find({
        login,
    }).toArray()
    if (!users.length) return fn(new Error('невозможно найти пользователя'))
    const [user] = users

    hash({
        password: pass, salt: user.salt,
    }, (err, pass, salt, hash) => {
        if (err) return fn(err)
        if (hash === user.hash) return fn(null, user)
        fn(new Error('неверный пароль'))
    })
}

const setUsers = async (dataUsers) => {
    if (db === null) throw new Error('no db connection')

    const usersCollection = db.collection(USERS_COLL)
    const data = await usersCollection.find({
        $or: [{
            login: dataUsers.login,
        }, {
            mail: dataUsers.mail,
        }],
    }).toArray()

    if (data.length === 0) {
        hash({
            password: dataUsers.password, saltLength: 15,
        }, (err, pass, salt, hash) => {
            const users = {
            }
            const { login, password, mail } = {
                ...dataUsers,
            }
            users.login = login
            users.name = login
            users.mail = mail
            users.hash = hash
            users.salt = salt
            usersCollection.insertMany([users])
        })

        return dataUsers
    }
    if (data.length !== 0) throw new Error('Почта или логин уже существует')
}

module.exports = {
    connect,
    getDepts,
    getDeptData,
    getPeoplesData,
    createDept,
    setUsers,
    deleteDeptById,
    authenticate,
}