//
//  SuggestedProfilesViewController.swift
//  Tusker
//
//  Created by Shadowfacts on 2/11/23.
//  Copyright © 2023 Shadowfacts. All rights reserved.
//

import UIKit
import Pachyderm

class SuggestedProfilesViewController: UIViewController, CollectionViewController {
    
    weak var mastodonController: MastodonController!
    
    var collectionView: UICollectionView!
    private var layout: MultiColumnCollectionViewLayout!
    private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
    
    private var state = State.unloaded
    
    init(mastodonController: MastodonController) {
        self.mastodonController = mastodonController
        
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        title = "Suggested Accounts"
        
        layout = MultiColumnCollectionViewLayout(numberOfColumns: 2, columnSpacing: 16, minimumColumnWidth: 320)
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        collectionView.delegate = self
        collectionView.dragDelegate = self
        collectionView.backgroundColor = .appGroupedBackground
        collectionView.allowsFocus = true
        view.addSubview(collectionView)
        NSLayoutConstraint.activate([
            collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            collectionView.topAnchor.constraint(equalTo: view.topAnchor),
            collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        ])
        
        dataSource = createDataSource()
    }
    
    private func createDataSource() -> UICollectionViewDiffableDataSource<Section, Item> {
        let accountCell = UICollectionView.CellRegistration<SuggestedProfileCardCollectionViewCell, (String, Suggestion.Source)>(cellNib: UINib(nibName: "SuggestedProfileCardCollectionViewCell", bundle: .main)) { cell, indexPath, item in
            cell.delegate = self
            cell.updateUI(accountID: item.0, source: item.1)
        }
        let dataSource =  UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in
            switch itemIdentifier {
            case .account(let id, let source):
                return collectionView.dequeueConfiguredReusableCell(using: accountCell, for: indexPath, item: (id, source))
            }
        }
        let loadingView = UICollectionView.SupplementaryRegistration<LoadingCollectionViewCell>(elementKind: UICollectionView.elementKindSectionHeader) { view, elementKind, indexPath in
            view.indicator.startAnimating()
        }
        dataSource.supplementaryViewProvider = { collectionView, elementKind, indexPath in
            if elementKind == UICollectionView.elementKindSectionHeader {
                return collectionView.dequeueConfiguredReusableSupplementary(using: loadingView, for: indexPath)
            } else {
                return nil
            }
        }
        return dataSource
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        Task {
            await loadInitial()
        }
    }
    
    @MainActor
    private func loadInitial() async {
        guard case .unloaded = state else {
            return
        }
        state = .loading
        
        layout.showSectionHeader = true
        
        var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
        snapshot.appendSections([.accounts])
        await dataSource.apply(snapshot)
        
        do {
            let request = Client.getSuggestions(limit: 80)
            let (suggestions, _) = try await mastodonController.run(request)
            
            await mastodonController.persistentContainer.addAll(accounts: suggestions.map(\.account))
            
            layout.showSectionHeader = false
            
            var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
            snapshot.appendSections([.accounts])
            snapshot.appendItems(suggestions.map { .account($0.account.id, $0.source) })
            await dataSource.apply(snapshot)
            
            state = .loaded
        } catch {
            state = .unloaded
            let config = ToastConfiguration(from: error, with: "Error Loading Suggested Accounts", in: self) { [weak self] toast in
                toast.dismissToast(animated: true)
                await self?.loadInitial()
            }
            showToast(configuration: config, animated: true)
            layout.showSectionHeader = false
        }
    }
    
}

extension SuggestedProfilesViewController {
    enum State {
        case unloaded
        case loading
        case loaded
    }
}

extension SuggestedProfilesViewController {
    enum Section {
        case accounts
    }
    enum Item: Hashable {
        case account(String, Suggestion.Source)
    }
}

extension SuggestedProfilesViewController: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
        if case .account(_, _) = dataSource.itemIdentifier(for: indexPath) {
            return true
        } else {
            return false
        }
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        guard case .account(let id, _) = dataSource.itemIdentifier(for: indexPath) else {
            return
        }
        selected(account: id)
    }
    
    func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
        guard case .account(let id, _) = dataSource.itemIdentifier(for: indexPath),
              let cell = collectionView.cellForItem(at: indexPath) else {
            return nil
        }
        return UIContextMenuConfiguration {
            ProfileViewController(accountID: id, mastodonController: self.mastodonController)
        } actionProvider: { _ in
            UIMenu(children: self.actionsForProfile(accountID: id, source: .view(cell)))
        }
    }
    
    func collectionView(_ collectionView: UICollectionView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) {
        MenuPreviewHelper.willPerformPreviewAction(animator: animator, presenter: self)
    }
}

extension SuggestedProfilesViewController: UICollectionViewDragDelegate {
    func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
        guard case .account(let id, _) = dataSource.itemIdentifier(for: indexPath),
              let account = mastodonController.persistentContainer.account(for: id) else {
            return []
        }
        let provider = NSItemProvider(object: account.url as NSURL)
        let activity = UserActivityManager.showProfileActivity(id: id, accountID: mastodonController.accountInfo!.id)
        provider.registerObject(activity, visibility: .all)
        return [UIDragItem(itemProvider: provider)]
    }
}

extension SuggestedProfilesViewController: TuskerNavigationDelegate {
    var apiController: MastodonController! { mastodonController }
}

extension SuggestedProfilesViewController: MenuActionProvider {
}

extension SuggestedProfilesViewController: ToastableViewController {
}
