//
//  AllFunctionsViewController.swift
//  suixinkan
//

import SnapKit
import UIKit

/// 全部功能页，管理常用应用与更多功能的增删。
final class AllFunctionsViewController: BaseViewController {

    var onDidCustomize: (() -> Void)?

    private enum AllFunctionSection: Int, CaseIterable, Hashable {
        case common
        case more

        var title: String {
            switch self {
            case .common: return "常用应用"
            case .more: return "更多功能"
            }
        }

        var actionStyle: AllFunctionMenuCell.ActionStyle {
            switch self {
            case .common: return .remove
            case .more: return .add
            }
        }
    }

    /// 全部功能列表中的展示项，包含分区信息以确保移动后重新配置操作图标。
    private struct AllFunctionListItem: Hashable {
        let section: AllFunctionSection
        let menu: HomeMenuItem

        var actionStyle: AllFunctionMenuCell.ActionStyle {
            section.actionStyle
        }
    }

    private let viewModel = AllFunctionsViewModel()
    private let collectionView: UICollectionView

    private var dataSource: UICollectionViewDiffableDataSource<AllFunctionSection, AllFunctionListItem>!
    private var hasAppliedInitialSnapshot = false

    init() {
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: Self.makeLayout())
        super.init(nibName: nil, bundle: nil)
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func setupNavigationBar() {
        title = "全部功能"
    }

    override func setupUI() {
        view.backgroundColor = AppColor.pageBackground

        collectionView.backgroundColor = .clear
        collectionView.alwaysBounceVertical = true
        collectionView.allowsSelection = true
        collectionView.delegate = self
        collectionView.contentInset = UIEdgeInsets(
            top: AppSpacing.xs,
            left: 0,
            bottom: AppSpacing.md,
            right: 0
        )
        collectionView.register(
            AllFunctionMenuCell.self,
            forCellWithReuseIdentifier: AllFunctionMenuCell.reuseIdentifier
        )
        collectionView.register(
            AllFunctionSectionHeaderView.self,
            forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
            withReuseIdentifier: AllFunctionSectionHeaderView.reuseIdentifier
        )

        dataSource = makeDataSource()
        view.addSubview(collectionView)
    }

    override func setupConstraints() {
        collectionView.snp.makeConstraints { make in
            make.top.leading.trailing.equalTo(view.safeAreaLayoutGuide)
            make.bottom.equalToSuperview()
        }
    }

    override func bindActions() {
        viewModel.onStateChange = { [weak self] in
            Task { @MainActor in
                self?.applyViewModel(animated: self?.hasAppliedInitialSnapshot == true)
            }
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        viewModel.loadFunctions()
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        if isMovingFromParent, viewModel.didCustomize {
            onDidCustomize?()
        }
    }

    @MainActor
    private func applyViewModel(animated: Bool) {
        var snapshot = NSDiffableDataSourceSnapshot<AllFunctionSection, AllFunctionListItem>()
        snapshot.appendSections([.common, .more])
        snapshot.appendItems(
            viewModel.commonMenus.map { AllFunctionListItem(section: .common, menu: $0) },
            toSection: .common
        )
        snapshot.appendItems(
            viewModel.moreMenus.map { AllFunctionListItem(section: .more, menu: $0) },
            toSection: .more
        )
        dataSource.apply(snapshot, animatingDifferences: animated)
        hasAppliedInitialSnapshot = true
    }

    private func makeDataSource() -> UICollectionViewDiffableDataSource<AllFunctionSection, AllFunctionListItem> {
        let dataSource = UICollectionViewDiffableDataSource<AllFunctionSection, AllFunctionListItem>(
            collectionView: collectionView
        ) { collectionView, indexPath, item in
            let cell = collectionView.dequeueReusableCell(
                withReuseIdentifier: AllFunctionMenuCell.reuseIdentifier,
                for: indexPath
            ) as! AllFunctionMenuCell
            cell.apply(menu: item.menu, actionStyle: item.actionStyle)
            return cell
        }

        dataSource.supplementaryViewProvider = { collectionView, kind, indexPath in
            guard kind == UICollectionView.elementKindSectionHeader,
                  let section = AllFunctionSection(rawValue: indexPath.section) else {
                return nil
            }
            let header = collectionView.dequeueReusableSupplementaryView(
                ofKind: kind,
                withReuseIdentifier: AllFunctionSectionHeaderView.reuseIdentifier,
                for: indexPath
            ) as! AllFunctionSectionHeaderView
            header.apply(title: section.title)
            return header
        }

        return dataSource
    }

    private static func makeLayout() -> UICollectionViewCompositionalLayout {
        UICollectionViewCompositionalLayout { sectionIndex, environment in
            let spacing: CGFloat = 15
            let columns = 3
            let horizontalInset = AppSpacing.md
            let availableWidth = environment.container.effectiveContentSize.width - horizontalInset * 2
            let totalSpacing = spacing * CGFloat(columns - 1)
            let itemWidth = max(0, (availableWidth - totalSpacing) / CGFloat(columns))

            let itemSize = NSCollectionLayoutSize(
                widthDimension: .absolute(itemWidth),
                heightDimension: .absolute(itemWidth)
            )
            let item = NSCollectionLayoutItem(layoutSize: itemSize)
            let groupSize = NSCollectionLayoutSize(
                widthDimension: .fractionalWidth(1),
                heightDimension: .absolute(itemWidth)
            )
            let group = NSCollectionLayoutGroup.horizontal(
                layoutSize: groupSize,
                repeatingSubitem: item,
                count: columns
            )
            group.interItemSpacing = .fixed(spacing)

            let section = NSCollectionLayoutSection(group: group)
            section.interGroupSpacing = spacing
            section.contentInsets = NSDirectionalEdgeInsets(
                top: 0,
                leading: horizontalInset,
                bottom: sectionIndex == AllFunctionSection.common.rawValue ? AppSpacing.lg : AppSpacing.md,
                trailing: horizontalInset
            )

            let headerSize = NSCollectionLayoutSize(
                widthDimension: .fractionalWidth(1),
                heightDimension: .absolute(36)
            )
            let header = NSCollectionLayoutBoundarySupplementaryItem(
                layoutSize: headerSize,
                elementKind: UICollectionView.elementKindSectionHeader,
                alignment: .top
            )
            section.boundarySupplementaryItems = [header]
            return section
        }
    }
}

extension AllFunctionsViewController: UICollectionViewDelegate {

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        guard let item = dataSource.itemIdentifier(for: indexPath) else { return }
        collectionView.deselectItem(at: indexPath, animated: true)

        switch item.section {
        case .common:
            viewModel.removeFromCommon(item.menu)
        case .more:
            viewModel.addToCommon(item.menu)
        }
    }
}

/// 全部功能页分区标题。
private final class AllFunctionSectionHeaderView: UICollectionReusableView {

    static let reuseIdentifier = "AllFunctionSectionHeaderView"

    private let titleLabel = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        titleLabel.font = .app(.title)
        titleLabel.textColor = AppColor.textPrimary
        addSubview(titleLabel)
        titleLabel.snp.makeConstraints { make in
            make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
            make.bottom.equalToSuperview().inset(AppSpacing.xs)
        }
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func apply(title: String) {
        titleLabel.text = title
    }
}
