/**
 * Conversations Service - Zero-Knowledge Chat Implementation
 * Handles encrypted messaging between users using participant hashes
 */

import { directus } from './directus.js'
import { cryptoService } from './crypto.js'

class ConversationsService {
    constructor() {
        this.pollingInterval = null
        this.subscribers = new Set()
    }

    async getParticipantHash() {
        await cryptoService.ready
        const publicKey = cryptoService.getPublicKey()
        return this.hashPublicKey(publicKey)
    }

    hashPublicKey(publicKey) {
        const encoder = new TextEncoder()
        const data = encoder.encode(publicKey)
        return crypto.subtle.digest('SHA-256', data).then(hash => {
            return Array.from(new Uint8Array(hash))
                .map(b => b.toString(16).padStart(2, '0'))
                .join('')
        })
    }

    async getMyConversations() {
        const participantHash = await this.getParticipantHash()
        const conversations = await directus.getConversations(participantHash)
        
        return conversations.map(conv => ({
            ...conv,
            isParticipant1: conv.participant_hash_1 === participantHash,
            otherParticipantHash: conv.participant_hash_1 === participantHash 
                ? conv.participant_hash_2 
                : conv.participant_hash_1,
            otherPublicKey: conv.participant_hash_1 === participantHash
                ? conv.public_key_2
                : conv.public_key_1
        }))
    }

    async getConversation(id) {
        const conversation = await directus.getConversation(id)
        if (!conversation) return null

        const participantHash = await this.getParticipantHash()
        
        return {
            ...conversation,
            isParticipant1: conversation.participant_hash_1 === participantHash,
            otherParticipantHash: conversation.participant_hash_1 === participantHash 
                ? conversation.participant_hash_2 
                : conversation.participant_hash_1,
            otherPublicKey: conversation.participant_hash_1 === participantHash
                ? conversation.public_key_2
                : conversation.public_key_1,
            myPublicKey: conversation.participant_hash_1 === participantHash
                ? conversation.public_key_1
                : conversation.public_key_2
        }
    }

    async getMessages(conversationId, otherPublicKey) {
        await cryptoService.ready
        
        const messages = await directus.getConversationMessages(conversationId)
        const myHash = await this.getParticipantHash()
        
        return messages.map(msg => {
            const isOwn = msg.sender_hash === myHash
            let text = '[Encrypted]'
            
            try {
                text = cryptoService.decrypt(msg.content_encrypted, msg.nonce, otherPublicKey)
            } catch (e) {
                text = '[Decryption failed]'
            }
            
            return {
                id: msg.id,
                text,
                isOwn,
                type: msg.type,
                timestamp: msg.date_created
            }
        })
    }

    async sendMessage(conversationId, otherPublicKey, plainText, type = 'text') {
        await cryptoService.ready
        
        const { nonce, ciphertext } = cryptoService.encrypt(plainText, otherPublicKey)
        const senderHash = await this.getParticipantHash()
        
        const message = await directus.sendMessage(
            conversationId,
            senderHash,
            ciphertext,
            nonce,
            type
        )
        
        this.notifySubscribers()
        
        return {
            id: message.id,
            text: plainText,
            isOwn: true,
            type: message.type,
            timestamp: message.date_created
        }
    }

    async startOrGetConversation(listingId, sellerPublicKey) {
        await cryptoService.ready
        
        const myPublicKey = cryptoService.getPublicKey()
        const myHash = await this.getParticipantHash()
        const sellerHash = await this.hashPublicKey(sellerPublicKey)
        
        const existing = await directus.findConversation(listingId, myHash, sellerHash)
        if (existing) {
            return this.getConversation(existing.id)
        }
        
        const newConv = await directus.startConversation(
            listingId,
            myHash,
            sellerHash,
            myPublicKey,
            sellerPublicKey
        )
        
        return this.getConversation(newConv.id)
    }

    async closeConversation(id) {
        return directus.updateConversationStatus(id, 'closed')
    }

    startPolling(intervalMs = 10000) {
        if (this.pollingInterval) return
        
        this.pollingInterval = setInterval(async () => {
            try {
                await this.getMyConversations()
                this.notifySubscribers()
            } catch (e) {
                console.warn('Conversation polling failed:', e)
            }
        }, intervalMs)
    }

    stopPolling() {
        if (this.pollingInterval) {
            clearInterval(this.pollingInterval)
            this.pollingInterval = null
        }
    }

    subscribe(callback) {
        this.subscribers.add(callback)
        return () => this.subscribers.delete(callback)
    }

    notifySubscribers() {
        this.subscribers.forEach(cb => cb())
    }
}

export const conversationsService = new ConversationsService()
