//
//  NotificationView+ViewModel.swift
//  
//
//  Created by MainasuK on 2022-1-21.
//

import os.log
import UIKit
import Combine
import Meta
import MastodonSDK
import MastodonAsset
import MastodonLocalization
import MastodonExtension

extension NotificationView {
    public final class ViewModel: ObservableObject {
        public var disposeBag = Set<AnyCancellable>()

        let logger = Logger(subsystem: "StatusView", category: "ViewModel")
        
        @Published public var userIdentifier: UserIdentifier?       // me
        
        @Published public var notificationIndicatorText: MetaContent?

        @Published public var authorAvatarImage: UIImage?
        @Published public var authorAvatarImageURL: URL?
        @Published public var authorName: MetaContent?
        @Published public var authorUsername: String?
        
        @Published public var isMyself = false
        @Published public var isMuting = false
        @Published public var isBlocking = false
        
        @Published public var timestamp: Date?
        
        let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common)
            .autoconnect()
            .share()
            .eraseToAnyPublisher()
        
    }
}

extension NotificationView.ViewModel {
    func bind(notificationView: NotificationView) {
        bindAuthor(notificationView: notificationView)
        bindAuthorMenu(notificationView: notificationView)
        
        $userIdentifier
            .assign(to: \.userIdentifier, on: notificationView.statusView.viewModel)
            .store(in: &disposeBag)
        $userIdentifier
            .assign(to: \.userIdentifier, on: notificationView.quoteStatusView.viewModel)
            .store(in: &disposeBag)
    }
 
    private func bindAuthor(notificationView: NotificationView) {
        // avatar
        Publishers.CombineLatest(
            $authorAvatarImage,
            $authorAvatarImageURL
        )
        .sink { image, url in
            let configuration: AvatarImageView.Configuration = {
                if let image = image {
                    return AvatarImageView.Configuration(image: image)
                } else {
                    return AvatarImageView.Configuration(url: url)
                }
            }()
            notificationView.avatarButton.avatarImageView.configure(configuration: configuration)
            notificationView.avatarButton.avatarImageView.configure(cornerConfiguration: .init(corner: .fixed(radius: 12)))
        }
        .store(in: &disposeBag)
        // name
        $authorName
            .sink { metaContent in
                let metaContent = metaContent ?? PlaintextMetaContent(string: " ")
                notificationView.authorNameLabel.configure(content: metaContent)
            }
            .store(in: &disposeBag)
        // username
        $authorUsername
            .map { text -> String in
                guard let text = text else { return "" }
                return "@\(text)"
            }
            .sink { username in
                let metaContent = PlaintextMetaContent(string: username)
                notificationView.authorUsernameLabel.configure(content: metaContent)
            }
            .store(in: &disposeBag)
        // timestamp
        Publishers.CombineLatest(
            $timestamp,
            timestampUpdatePublisher.prepend(Date()).eraseToAnyPublisher()
        )
        .sink { [weak self] timestamp, _ in
            guard let self = self else { return }
            guard let timestamp = timestamp else {
                notificationView.dateLabel.configure(content: PlaintextMetaContent(string: ""))
                return
            }
            
            let text = timestamp.localizedTimeAgoSinceNow
            notificationView.dateLabel.configure(content: PlaintextMetaContent(string: text))
        }
        .store(in: &disposeBag)
        // notification type indicator
        $notificationIndicatorText
            .sink { text in
                if let text = text {
                    notificationView.notificationTypeIndicatorLabel.configure(content: text)
                } else {
                    notificationView.notificationTypeIndicatorLabel.reset()
                }
            }
            .store(in: &disposeBag)
    }
    
    private func bindAuthorMenu(notificationView: NotificationView) {
        Publishers.CombineLatest4(
            $authorName,
            $isMuting,
            $isBlocking,
            $isMyself
        )
        .sink { authorName, isMuting, isBlocking, isMyself in
            guard let name = authorName?.string else {
                notificationView.menuButton.menu = nil
                return
            }
            
            let menuContext = NotificationView.AuthorMenuContext(
                name: name,
                isMuting: isMuting,
                isBlocking: isBlocking,
                isMyself: isMyself
            )
            notificationView.menuButton.menu = notificationView.setupAuthorMenu(menuContext: menuContext)
            notificationView.menuButton.showsMenuAsPrimaryAction = true
            
            notificationView.menuButton.isHidden = menuContext.isMyself
        }
        .store(in: &disposeBag)
    }
}
