import Foundation
import Combine

struct ChatNavigationTarget: Identifiable {
    let id = UUID()
    let chat: PrivateChatListItem
}

final class IncomingMessageCenter: ObservableObject {
    @Published private(set) var banner: IncomingMessageBanner?
    @Published var presentedChat: PrivateChatListItem?
    @Published var pendingNavigation: ChatNavigationTarget?
    var currentUserId: String?
    var activeChatId: String?

    private var dismissWorkItem: DispatchWorkItem?
    private var cancellables = Set<AnyCancellable>()
    private let notificationCenter: NotificationCenter

    init(notificationCenter: NotificationCenter = .default) {
        self.notificationCenter = notificationCenter
        notificationCenter.publisher(for: .socketDidReceivePrivateMessage)
            .compactMap { $0.object as? MessageItem }
            .receive(on: RunLoop.main)
            .sink { [weak self] message in
                self?.handleIncoming(message)
            }
            .store(in: &cancellables)
    }

    func dismissBanner() {
        dismissWorkItem?.cancel()
        dismissWorkItem = nil
        banner = nil
    }

    func openCurrentChat() {
        guard let banner else { return }
        activeChatId = banner.message.chatId
        let chatItem = makeChatItem(from: banner.message)
        if AppConfig.PRESENT_CHAT_AS_SHEET {
            presentedChat = chatItem
            pendingNavigation = nil
        } else {
            pendingNavigation = ChatNavigationTarget(chat: chatItem)
            presentedChat = nil
        }
        dismissBanner()
    }

    private func handleIncoming(_ message: MessageItem) {
        if let currentUserId, message.senderId == currentUserId {
            return
        }

        if let activeChatId, activeChatId == message.chatId {
            return
        }

        if AppConfig.PRESENT_CHAT_AS_SHEET,
           let presentedChat,
           presentedChat.chatId == message.chatId {
            return
        }

        banner = buildBanner(from: message)
        scheduleDismiss()
    }

    private func buildBanner(from message: MessageItem) -> IncomingMessageBanner {
        let sender = senderName(for: message)
        let preview = messagePreview(for: message)
        return IncomingMessageBanner(message: message, senderName: sender, messagePreview: preview)
    }

    private func senderName(for message: MessageItem) -> String {
        let candidates: [String?] = [
            message.senderData?.customName,
            message.senderData?.fullName,
            message.senderData?.login.map { "@\($0)" }
        ]

        for candidate in candidates {
            if let value = candidate?.trimmingCharacters(in: .whitespacesAndNewlines), !value.isEmpty {
                return value
            }
        }

        return message.senderId
    }

    private func messagePreview(for message: MessageItem) -> String {
        if let content = message.content?.trimmingCharacters(in: .whitespacesAndNewlines), !content.isEmpty {
            return content
        }

        switch message.messageType.lowercased() {
        case "image":
            return NSLocalizedString("Изображение", comment: "Image message placeholder")
        case "audio":
            return NSLocalizedString("Аудио", comment: "Audio message placeholder")
        case "video":
            return NSLocalizedString("Видео", comment: "Video message placeholder")
        default:
            return NSLocalizedString("Новое сообщение", comment: "Default banner subtitle")
        }
    }

    private func makeChatItem(from message: MessageItem) -> PrivateChatListItem {
        let profile = message.senderData
        return PrivateChatListItem(
            chatId: message.chatId,
            chatType: .privateChat,
            chatData: profile,
            lastMessage: message,
            createdAt: message.createdAt,
            unreadCount: 0
        )
    }

    private func scheduleDismiss(after delay: TimeInterval = 5) {
        dismissWorkItem?.cancel()
        let workItem = DispatchWorkItem { [weak self] in
            self?.banner = nil
            self?.dismissWorkItem = nil
        }
        dismissWorkItem = workItem
        DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: workItem)
    }
}
