//
//  ThreadModel.swift
//  damus
//
//  Created by William Casarin on 2022-04-19.
//

import Foundation

/// manages the lifetime of a thread
class ThreadModel: ObservableObject {
    @Published var event: NostrEvent
    let original_event: NostrEvent
    var event_map: Set<NostrEvent>
    
    init(event: NostrEvent, damus_state: DamusState) {
        self.damus_state = damus_state
        self.event_map = Set()
        self.event = event
        self.original_event = event
        add_event(event, keypair: damus_state.keypair)
    }
    
    var is_original: Bool {
        return original_event.id == event.id
    }
    
    let damus_state: DamusState
    
    let profiles_subid = UUID().description
    let base_subid = UUID().description
    let meta_subid = UUID().description
    
    var subids: [String] {
        return [profiles_subid, base_subid, meta_subid]
    }
    
    func unsubscribe() {
        self.damus_state.pool.remove_handler(sub_id: base_subid)
        self.damus_state.pool.remove_handler(sub_id: meta_subid)
        self.damus_state.pool.remove_handler(sub_id: profiles_subid)
        self.damus_state.pool.unsubscribe(sub_id: base_subid)
        self.damus_state.pool.unsubscribe(sub_id: meta_subid)
        self.damus_state.pool.unsubscribe(sub_id: profiles_subid)
        print("unsubscribing from thread \(event.id) with sub_id \(base_subid)")
    }
    
    @discardableResult
    func set_active_event(_ ev: NostrEvent, keypair: Keypair) -> Bool {
        self.event = ev
        add_event(ev, keypair: keypair)

        //self.objectWillChange.send()
        return false
    }
    
    func subscribe() {
        var meta_events = NostrFilter()
        var event_filter = NostrFilter()
        var ref_events = NostrFilter()

        let thread_id = event.thread_id(keypair: .empty)

        ref_events.referenced_ids = [thread_id, event.id]
        ref_events.kinds = [.text]
        ref_events.limit = 1000
        
        event_filter.ids = [thread_id, event.id]
        
        meta_events.referenced_ids = [event.id]

        var kinds: [NostrKind] = [.zap, .text, .boost]
        if !damus_state.settings.onlyzaps_mode {
            kinds.append(.like)
        }
        meta_events.kinds = kinds

        meta_events.limit = 1000
        
        let base_filters = [event_filter, ref_events]
        let meta_filters = [meta_events]

        print("subscribing to thread \(event.id) with sub_id \(base_subid)")
        damus_state.pool.subscribe(sub_id: base_subid, filters: base_filters, handler: handle_event)
        damus_state.pool.subscribe(sub_id: meta_subid, filters: meta_filters, handler: handle_event)
    }
    
    func add_event(_ ev: NostrEvent, keypair: Keypair) {
        if event_map.contains(ev) {
            return
        }
        
        let the_ev = damus_state.events.upsert(ev)
        damus_state.replies.count_replies(ev, keypair: keypair)
        damus_state.events.add_replies(ev: ev, keypair: keypair)

        event_map.insert(ev)
        objectWillChange.send()
    }

    @MainActor
    func handle_event(relay_id: String, ev: NostrConnectionEvent) {
        
        let (sub_id, done) = handle_subid_event(pool: damus_state.pool, relay_id: relay_id, ev: ev) { sid, ev in
            guard subids.contains(sid) else {
                return
            }
            
            if ev.known_kind == .zap {
                process_zap_event(damus_state: damus_state, ev: ev) { zap in
                    
                }
            } else if ev.is_textlike {
                self.add_event(ev, keypair: damus_state.keypair)
            }
        }
        
        guard done, let sub_id, subids.contains(sub_id) else {
            return
        }
        
        if sub_id == self.base_subid {
            let txn = NdbTxn(ndb: damus_state.ndb)
            load_profiles(context: "thread", profiles_subid: self.profiles_subid, relay_id: relay_id, load: .from_events(Array(event_map)), damus_state: damus_state, txn: txn)
        }
    }

}


func get_top_zap(events: EventCache, evid: NoteId) -> Zapping? {
    return events.get_cache_data(evid).zaps_model.zaps.first(where: { zap in
        !zap.request.marked_hidden
    })
}
