//
//  SuggestionAccountViewController.swift
//  Mastodon
//
//  Created by sxiaojian on 2021/4/21.
//

import Combine
import CoreData
import CoreDataStack
import Foundation
import OSLog
import UIKit

class SuggestionAccountViewController: UIViewController, NeedsDependency {
    weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
    weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }

    var disposeBag = Set<AnyCancellable>()

    var viewModel: SuggestionAccountViewModel!

    let tableView: UITableView = {
        let tableView = ControlContainableTableView()
        tableView.register(SuggestionAccountTableViewCell.self, forCellReuseIdentifier: String(describing: SuggestionAccountTableViewCell.self))
        tableView.rowHeight = UITableView.automaticDimension
        tableView.tableFooterView = UIView()
        tableView.separatorStyle = .singleLine
        tableView.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        return tableView
    }()

    lazy var tableHeader: UIView = {
        let view = UIView()
        view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
        view.frame = CGRect(origin: .zero, size: CGSize(width: tableView.frame.width, height: 156))
        return view
    }()

    let followExplainLabel: UILabel = {
        let label = UILabel()
        label.text = L10n.Scene.SuggestionAccount.followExplain
        label.textColor = Asset.Colors.Label.primary.color
        label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular))
        label.numberOfLines = 0
        return label
    }()

    let selectedCollectionView: UICollectionView = {
        let flowLayout = UICollectionViewFlowLayout()
        flowLayout.scrollDirection = .horizontal
        let view = ControlContainableCollectionView(frame: .zero, collectionViewLayout: flowLayout)
        view.register(SuggestionAccountCollectionViewCell.self, forCellWithReuseIdentifier: String(describing: SuggestionAccountCollectionViewCell.self))
        view.backgroundColor = .clear
        view.showsHorizontalScrollIndicator = false
        view.showsVerticalScrollIndicator = false
        view.layer.masksToBounds = false
        return view
    }()

    deinit {
        os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s:", (#file as NSString).lastPathComponent, #line, #function)
    }
}

extension SuggestionAccountViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = Asset.Colors.Background.systemBackground.color
        title = L10n.Scene.SuggestionAccount.title
        navigationItem.rightBarButtonItem
            = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.done,
                              target: self,
                              action: #selector(SuggestionAccountViewController.doneButtonDidClick(_:)))

        tableView.delegate = self
        tableView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(tableView)
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: view.topAnchor),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        ])
        viewModel.diffableDataSource = RecommendAccountSection.tableViewDiffableDataSource(
            for: tableView,
            managedObjectContext: context.managedObjectContext,
            viewModel: viewModel,
            delegate: self
        )

        viewModel.collectionDiffableDataSource = SelectedAccountSection.collectionViewDiffableDataSource(for: selectedCollectionView, managedObjectContext: context.managedObjectContext)

        viewModel.accounts
            .receive(on: DispatchQueue.main)
            .sink { [weak self] accounts in
                guard let self = self else { return }
                self.setupHeader(accounts: accounts)
            }
            .store(in: &disposeBag)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        tableView.deselectRow(with: transitionCoordinator, animated: animated)
        viewModel.checkAccountsFollowState()
    }

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        let avatarImageViewHeight: Double = 56
        let avatarImageViewCount = Int(floor((Double(view.frame.width) - 20) / (avatarImageViewHeight + 15)))
        viewModel.headerPlaceholderCount.value = avatarImageViewCount
    }

    func setupHeader(accounts: [NSManagedObjectID]) {
        if accounts.isEmpty {
            return
        }
        followExplainLabel.translatesAutoresizingMaskIntoConstraints = false
        tableHeader.addSubview(followExplainLabel)
        NSLayoutConstraint.activate([
            followExplainLabel.topAnchor.constraint(equalTo: tableHeader.topAnchor, constant: 20),
            followExplainLabel.leadingAnchor.constraint(equalTo: tableHeader.leadingAnchor, constant: 20),
            tableHeader.trailingAnchor.constraint(equalTo: followExplainLabel.trailingAnchor, constant: 20),
        ])

        selectedCollectionView.translatesAutoresizingMaskIntoConstraints = false
        tableHeader.addSubview(selectedCollectionView)
        NSLayoutConstraint.activate([
            selectedCollectionView.frameLayoutGuide.topAnchor.constraint(equalTo: followExplainLabel.topAnchor, constant: 20),
            selectedCollectionView.frameLayoutGuide.leadingAnchor.constraint(equalTo: tableHeader.leadingAnchor, constant: 20),
            selectedCollectionView.frameLayoutGuide.trailingAnchor.constraint(equalTo: tableHeader.trailingAnchor),
            selectedCollectionView.frameLayoutGuide.bottomAnchor.constraint(equalTo: tableHeader.bottomAnchor),
        ])
        selectedCollectionView.delegate = self

        tableView.tableHeaderView = tableHeader
    }
}

extension SuggestionAccountViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        15
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        CGSize(width: 56, height: 56)
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        guard let diffableDataSource = viewModel.collectionDiffableDataSource else { return }
        guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
        switch item {
        case .accountObjectID(let accountObjectID):
            let mastodonUser = context.managedObjectContext.object(with: accountObjectID) as! MastodonUser
            let viewModel = ProfileViewModel(context: context, optionalMastodonUser: mastodonUser)
            DispatchQueue.main.async {
                self.coordinator.present(scene: .profile(viewModel: viewModel), from: self, transition: .show)
            }
        default:
            break
        }
    }
}

extension SuggestionAccountViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        guard let diffableDataSource = viewModel.diffableDataSource else { return }
        guard let objectID = diffableDataSource.itemIdentifier(for: indexPath) else { return }
        let mastodonUser = context.managedObjectContext.object(with: objectID) as! MastodonUser
        let viewModel = ProfileViewModel(context: context, optionalMastodonUser: mastodonUser)
        DispatchQueue.main.async {
            self.coordinator.present(scene: .profile(viewModel: viewModel), from: self, transition: .show)
        }
    }
}

extension SuggestionAccountViewController: SuggestionAccountTableViewCellDelegate {
    func accountButtonPressed(objectID: NSManagedObjectID, cell: SuggestionAccountTableViewCell) {
        let selected = !viewModel.selectedAccounts.value.contains(objectID)
        cell.startAnimating()
        viewModel.followAction(objectID: objectID)?
            .sink(receiveCompletion: { [weak self] completion in
                guard let self = self else { return }
                cell.stopAnimating()
                switch completion {
                case .failure(let error):
                    os_log("%{public}s[%{public}ld], %{public}s: follow failed. %s", (#file as NSString).lastPathComponent, #line, #function, error.localizedDescription)
                case .finished:
                    var selectedAccounts = self.viewModel.selectedAccounts.value
                    if selected {
                        selectedAccounts.append(objectID)
                    } else {
                        selectedAccounts.removeAll { $0 == objectID }
                    }
                    cell.button.isSelected = selected
                    self.viewModel.selectedAccounts.value = selectedAccounts
                }
            }, receiveValue: { _ in
            })
            .store(in: &disposeBag)
    }
}

extension SuggestionAccountViewController {
    @objc func doneButtonDidClick(_ sender: UIButton) {
        dismiss(animated: true, completion: nil)
        if viewModel.selectedAccounts.value.count > 0 {
            viewModel.delegate?.homeTimelineNeedRefresh.send()
        }
    }
}
