import HUD
import UIKit
import Shared
import Models
import Combine
import XXModels
import Defaults
import Integration
import DependencyInjection

enum SearchSection {
    case chats
    case connections
}

//enum SearchItem: Equatable, Hashable {
//    case chat(Chat)
//    case connection(Contact)
//}

typealias RecentsSnapshot = NSDiffableDataSourceSnapshot<SectionId, Contact>
//typealias SearchSnapshot = NSDiffableDataSourceSnapshot<SearchSection, SearchItem>

final class ChatListViewModel {
    @Dependency private var session: SessionType

    var isOnline: AnyPublisher<Bool, Never> {
        session.isOnline
    }

//    var chatsPublisher: AnyPublisher<[Chat], Never> {
//        chatsSubject.eraseToAnyPublisher()
//    }

    var hudPublisher: AnyPublisher<HUDStatus, Never> {
        hudSubject.eraseToAnyPublisher()
    }

//    var recentsPublisher: AnyPublisher<RecentsSnapshot, Never> {
//        session.contacts(.isRecent).map {
//            let section = SectionId()
//            var snapshot = RecentsSnapshot()
//            snapshot.appendSections([section])
//            snapshot.appendItems($0, toSection: section)
//            return snapshot
//        }.eraseToAnyPublisher()
//    }

//    var searchPublisher: AnyPublisher<SearchSnapshot, Never> {
//        Publishers.CombineLatest3(
//            session.contacts(.all),
//            chatsPublisher,
//            searchSubject
//                .removeDuplicates()
//                .debounce(for: .milliseconds(100), scheduler: DispatchQueue.main)
//                .eraseToAnyPublisher()
//        )
//            .map { (contacts, chats, query) in
//                let connectionItems = contacts.filter {
//                    let username = $0.username.lowercased().contains(query.lowercased())
//                    let nickname = $0.nickname?.lowercased().contains(query.lowercased()) ?? false
//                    return username || nickname
//                }.map(SearchItem.connection)
//
//                let chatItems = chats.filter {
//                    switch $0 {
//                    case .contact(let info):
//                        let username = info.contact.username.lowercased().contains(query.lowercased())
//                        let nickname = info.contact.nickname?.lowercased().contains(query.lowercased()) ?? false
//                        let lastMessage = info.lastMessage?.payload.text.lowercased().contains(query.lowercased()) ?? false
//                        return username || nickname || lastMessage
//
//                    case .group(let info):
//                        let name = info.group.name.lowercased().contains(query.lowercased())
//                        let last = info.lastMessage?.payload.text.lowercased().contains(query.lowercased()) ?? false
//                        return name || last
//                    }
//                }.map(SearchItem.chat)
//
//                var snapshot = SearchSnapshot()
//
//                if connectionItems.count > 0 {
//                    snapshot.appendSections([.connections])
//                    snapshot.appendItems(connectionItems, toSection: .connections)
//                }
//
//                if chatItems.count > 0 {
//                    snapshot.appendSections([.chats])
//                    snapshot.appendItems(chatItems, toSection: .chats)
//                }
//
//                return snapshot
//            }.eraseToAnyPublisher()
//    }
//
//    var badgeCountPublisher: AnyPublisher<Int, Never> {
//        Publishers.CombineLatest(
//            session.contacts(.received),
//            session.groups(.pending)
//        )
//        .map { $0.0.count + $0.1.count }
//        .eraseToAnyPublisher()
//    }

    private var cancellables = Set<AnyCancellable>()
    private let searchSubject = CurrentValueSubject<String, Never>("")
//    private let chatsSubject = CurrentValueSubject<[Chat], Never>([])
    private let hudSubject = CurrentValueSubject<HUDStatus, Never>(.none)

    init() {
//        Publishers.CombineLatest(
//            session.singleChats(.all),
//            session.groupChats(.accepted)
//        ).map {
//            let groups = $0.1.map(Chat.group)
//            let chats = $0.0.map(Chat.contact)
//            return (chats + groups).sorted { $0.orderingDate > $1.orderingDate }
//        }
//        .sink { [unowned self] in chatsSubject.send($0) }
//        .store(in: &cancellables)
    }

    func updateSearch(query: String) {
        searchSubject.send(query)
    }

    func leave(_ group: Group) {
        hudSubject.send(.on(nil))

        do {
            try session.leave(group: group)
            try session.dbManager.deleteMessages(.init(chat: .group(group.id)))
            hudSubject.send(.none)
        } catch {
            hudSubject.send(.error(.init(with: error)))
        }
    }

    func clear(_ contact: Contact) {
        _ = try? session.dbManager.deleteMessages(.init(chat: .direct(session.myId, contact.id)))
    }
}