import { parentPort } from 'node:worker_threads'
import { PeerInfo, QuestionDb, User } from '../../types/basicTypes'
import { files, readAndValidateFile } from '../../utils/files'
import logger from '../../utils/logger'
import { peerToString, loginAndPostDataToAllPeers } from '../../utils/p2putils'
import { post } from '../../utils/networkUtils'
import { encrypt } from '../../utils/encryption'

export type UsersToPeersTaskObject = {
    type: 'sendUsersToPeers'
    data: {
        newUsers: (Omit<User, 'id'> & { id?: number })[]
    }
}

export const handleUsersToPeers = async (
    _qdbs: QuestionDb[],
    msg: UsersToPeersTaskObject,
    workerIndex: number
): Promise<void> => {
    const { newUsers } = msg.data

    const selfInfo = readAndValidateFile<PeerInfo>(files.selfInfoFile)
    const host = peerToString(selfInfo)
    const peers = readAndValidateFile<PeerInfo[]>(files.peersFile)

    if (!peers || peers.length === 0 || newUsers.length === 0) {
        parentPort.postMessage({
            msg: `From thread #${workerIndex}: sendUsersToPeers done`,
            workerIndex: workerIndex,
        })
        return
    }

    const postData = (peer: PeerInfo, sessionCookie: string) => {
        if (!peer.publicKey) {
            logger.Log(
                `"${peerToString(peer)}" has no public key saved!`,
                'yellowbg'
            )

            return Promise.resolve({
                error: new Error(
                    `"${peerToString(peer)}" has no public key saved!`
                ),
            })
        }

        const encryptedUsers = encrypt(peer.publicKey, JSON.stringify(newUsers))

        const dataToSend: { host: string; newUsers: string } = {
            host: host,
            newUsers: encryptedUsers,
        }

        return post<{
            addedUserCount?: number
            result?: string
            success?: boolean
        }>({
            hostname: peer.host,
            port: peer.port,
            http: peer.http,
            path: '/api/newusercreated',
            bodyObject: dataToSend,
            cookie: `sessionID=${sessionCookie}`,
        })
    }

    const newUserAdded: string[] = []
    loginAndPostDataToAllPeers<{
        addedUserCount?: number
        result?: string
        success?: boolean
    }>(peers, postData, (peer, res) => {
        if (res.data?.addedUserCount > 0) {
            newUserAdded.push(peerToString(peer))
        }
    })

    if (newUserAdded.length > 0) {
        logger.Log(
            `Peers that saved new users: ${newUserAdded.join(', ')}`,
            'cyan'
        )
    }

    parentPort.postMessage({
        msg: `From thread #${workerIndex}: sendUsersToPeers done`,
        workerIndex: workerIndex,
    })
}
