//
//  CloudStoragePickForTaskViewController.swift
//  suixinkan
//

import Kingfisher
import SnapKit
import UIKit

/// 任务云盘多选页，对齐 Android `CloudStorageListForTaskScreen`。
final class CloudStoragePickForTaskViewController: BaseViewController {

    var onConfirmed: (([CloudFile]) -> Void)?

    private let viewModel: CloudStoragePickForTaskViewModel
    private let taskAPI = NetworkServices.shared.taskAPI

    private let searchField = UITextField()
    private let pathScrollView = UIScrollView()
    private let pathStack = UIStackView()
    private let filterBar = UIStackView()
    private let sortButton = UIButton(type: .system)
    private let typeButton = UIButton(type: .system)
    private let displayModeButton = UIButton(type: .system)
    private let refreshControl = UIRefreshControl()
    private var collectionView: UICollectionView!
    private var dataSource: UICollectionViewDiffableDataSource<Int, Int>!
    private let confirmButton = AppButton(title: "确定")
    private let bottomBar = UIView()
    private var isGridMode = true

    /// 初始化云盘多选页，可按云盘文件类型限制选择范围。
    init(importedFileIDs: Set<Int> = [], allowedFileType: Int? = nil) {
        viewModel = CloudStoragePickForTaskViewModel(importedFileIDs: importedFileIDs, allowedFileType: allowedFileType)
        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() {
        searchField.placeholder = "搜索文件"
        searchField.borderStyle = .roundedRect
        searchField.font = .app(.body)
        searchField.returnKeyType = .search
        searchField.delegate = self

        pathStack.axis = .horizontal
        pathStack.spacing = AppSpacing.xs
        pathScrollView.showsHorizontalScrollIndicator = false
        pathScrollView.addSubview(pathStack)
        pathStack.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.height.equalToSuperview()
        }

        configureMenuButton(sortButton, imageName: "arrow.up.arrow.down")
        configureMenuButton(typeButton, imageName: "line.3.horizontal.decrease")
        displayModeButton.tintColor = AppColor.textSecondary
        displayModeButton.backgroundColor = AppColor.inputBackground
        displayModeButton.layer.cornerRadius = AppRadius.xs
        displayModeButton.addTarget(self, action: #selector(displayModeTapped), for: .touchUpInside)

        filterBar.axis = .horizontal
        filterBar.spacing = AppSpacing.sm
        filterBar.distribution = .fill
        filterBar.addArrangedSubview(sortButton)
        filterBar.addArrangedSubview(typeButton)
        filterBar.addArrangedSubview(displayModeButton)

        collectionView = UICollectionView(frame: .zero, collectionViewLayout: makeLayout())
        collectionView.backgroundColor = AppColor.pageBackground
        collectionView.register(CloudPickCell.self, forCellWithReuseIdentifier: CloudPickCell.reuseIdentifier)
        collectionView.delegate = self
        collectionView.refreshControl = refreshControl
        refreshControl.addTarget(self, action: #selector(refreshTriggered), for: .valueChanged)

        dataSource = UICollectionViewDiffableDataSource<Int, Int>(collectionView: collectionView) {
            [weak self] collectionView, indexPath, fileID in
            let cell = collectionView.dequeueReusableCell(
                withReuseIdentifier: CloudPickCell.reuseIdentifier,
                for: indexPath
            ) as! CloudPickCell
            if let file = self?.viewModel.files.first(where: { $0.id == fileID }) {
                cell.apply(
                    file: file,
                    isSelected: self?.viewModel.isSelected(fileID) == true,
                    isImported: self?.viewModel.isImported(fileID) == true,
                    isGridMode: self?.isGridMode == true
                )
            }
            return cell
        }

        bottomBar.backgroundColor = .white
        view.addSubview(searchField)
        view.addSubview(pathScrollView)
        view.addSubview(filterBar)
        view.addSubview(collectionView)
        view.addSubview(bottomBar)
        bottomBar.addSubview(confirmButton)
    }

    override func setupConstraints() {
        searchField.snp.makeConstraints { make in
            make.top.equalTo(view.safeAreaLayoutGuide).offset(AppSpacing.sm)
            make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
            make.height.equalTo(40)
        }
        pathScrollView.snp.makeConstraints { make in
            make.top.equalTo(searchField.snp.bottom).offset(AppSpacing.sm)
            make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
            make.height.equalTo(28)
        }
        filterBar.snp.makeConstraints { make in
            make.top.equalTo(pathScrollView.snp.bottom).offset(AppSpacing.sm)
            make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
            make.height.equalTo(36)
        }
        sortButton.snp.makeConstraints { make in make.width.equalTo(typeButton) }
        displayModeButton.snp.makeConstraints { make in make.width.equalTo(36) }
        bottomBar.snp.makeConstraints { make in
            make.leading.trailing.bottom.equalToSuperview()
        }
        confirmButton.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(AppSpacing.md)
        }
        collectionView.snp.makeConstraints { make in
            make.top.equalTo(filterBar.snp.bottom).offset(AppSpacing.md)
            make.leading.trailing.equalToSuperview()
            make.bottom.equalTo(bottomBar.snp.top)
        }
    }

    override func bindActions() {
        viewModel.onStateChange = { [weak self] in
            Task { @MainActor in self?.applyViewModel() }
        }
        viewModel.onShowMessage = { [weak self] message in
            Task { @MainActor in self?.showToast(message) }
        }
        confirmButton.addTarget(self, action: #selector(confirmTapped), for: .touchUpInside)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        Task { await viewModel.refresh(api: taskAPI) }
    }

    @MainActor
    private func applyViewModel() {
        rebuildPathButtons()
        rebuildFilterMenus()
        var snapshot = NSDiffableDataSourceSnapshot<Int, Int>()
        snapshot.appendSections([0])
        snapshot.appendItems(viewModel.files.map(\.id))
        let existingItems = Set(dataSource.snapshot().itemIdentifiers)
        let itemsToReconfigure = snapshot.itemIdentifiers.filter(existingItems.contains)
        snapshot.reconfigureItems(itemsToReconfigure)
        dataSource.apply(snapshot, animatingDifferences: false)
        let selectedCount = viewModel.selectedFileList.count
        confirmButton.setTitle(selectedCount > 0 ? "确认选择(\(selectedCount))" : "确认选择", for: .normal)
        if viewModel.isLoading && viewModel.files.isEmpty {
            showLoading()
        } else {
            hideLoading()
        }
        if !viewModel.isRefreshing {
            refreshControl.endRefreshing()
        }
    }

    private func rebuildPathButtons() {
        pathStack.arrangedSubviews.forEach { $0.removeFromSuperview() }
        for (index, item) in viewModel.pathStack.enumerated() {
            let button = UIButton(type: .system)
            button.setTitle(item.name, for: .normal)
            button.titleLabel?.font = .app(.caption)
            button.tag = index
            button.addTarget(self, action: #selector(pathTapped(_:)), for: .touchUpInside)
            pathStack.addArrangedSubview(button)
            if index < viewModel.pathStack.count - 1 {
                let arrow = UILabel()
                arrow.text = ">"
                arrow.font = .app(.caption)
                arrow.textColor = AppColor.textTertiary
                pathStack.addArrangedSubview(arrow)
            }
        }
    }

    @objc private func pathTapped(_ sender: UIButton) {
        Task { await viewModel.navigateToPathIndex(sender.tag, api: taskAPI) }
    }

    @objc private func confirmTapped() {
        guard !viewModel.selectedFileList.isEmpty else {
            showToast("请至少选择一个文件")
            return
        }
        onConfirmed?(viewModel.selectedFileList)
        navigationController?.popViewController(animated: true)
    }

    @objc private func refreshTriggered() {
        Task { await viewModel.refresh(api: taskAPI) }
    }

    @objc private func displayModeTapped() {
        isGridMode.toggle()
        collectionView.setCollectionViewLayout(makeLayout(), animated: true)
        applyViewModel()
    }

    private func configureMenuButton(_ button: UIButton, imageName: String) {
        button.tintColor = AppColor.textSecondary
        button.backgroundColor = AppColor.inputBackground
        button.layer.cornerRadius = AppRadius.xs
        button.contentHorizontalAlignment = .leading
        button.titleLabel?.font = .app(.body)
        button.setTitleColor(AppColor.textPrimary, for: .normal)
        button.setImage(UIImage(systemName: imageName), for: .normal)
        button.semanticContentAttribute = .forceRightToLeft
        button.showsMenuAsPrimaryAction = true
    }

    private func rebuildFilterMenus() {
        let sortItems = [(1, "创建时间顺序"), (2, "创建时间倒序")]
        sortButton.setTitle(sortItems.first(where: { $0.0 == viewModel.sortType })?.1 ?? "排序", for: .normal)
        sortButton.menu = UIMenu(children: sortItems.map { value, title in
            UIAction(title: title, state: value == viewModel.sortType ? .on : .off) { [weak self] _ in
                guard let self else { return }
                self.viewModel.updateSortType(value)
                Task { await self.viewModel.refresh(api: self.taskAPI) }
            }
        })

        let typeItems = [(0, "全部"), (2, "图片"), (1, "视频"), (99, "文件夹")]
        typeButton.setTitle(typeItems.first(where: { $0.0 == viewModel.filterType })?.1 ?? "全部", for: .normal)
        typeButton.menu = UIMenu(children: typeItems.map { value, title in
            UIAction(title: title, state: value == viewModel.filterType ? .on : .off) { [weak self] _ in
                guard let self else { return }
                self.viewModel.updateFilterType(value)
                Task { await self.viewModel.refresh(api: self.taskAPI) }
            }
        })
        displayModeButton.setImage(
            UIImage(systemName: isGridMode ? "list.bullet" : "square.grid.2x2"),
            for: .normal
        )
        displayModeButton.accessibilityLabel = isGridMode ? "列表显示" : "宫格显示"
    }

    private func makeLayout() -> UICollectionViewCompositionalLayout {
        let isGridMode = isGridMode
        return UICollectionViewCompositionalLayout { _, environment in
            let columns = isGridMode ? 2 : 1
            let spacing: CGFloat = 8
            let inset = AppSpacing.md * 2
            let availableWidth = environment.container.effectiveContentSize.width - inset
            let totalSpacing = spacing * CGFloat(columns - 1)
            let itemWidth = max(0, (availableWidth - totalSpacing) / CGFloat(columns))
            let itemHeight = isGridMode ? itemWidth + 38 : 72
            let itemSize = NSCollectionLayoutSize(
                widthDimension: .absolute(itemWidth),
                heightDimension: .absolute(itemHeight)
            )
            let item = NSCollectionLayoutItem(layoutSize: itemSize)
            let groupSize = NSCollectionLayoutSize(
                widthDimension: .fractionalWidth(1),
                heightDimension: .absolute(itemHeight)
            )
            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: AppSpacing.md,
                bottom: AppSpacing.md,
                trailing: AppSpacing.md
            )
            return section
        }
    }
}

extension CloudStoragePickForTaskViewController: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        guard let fileID = dataSource.itemIdentifier(for: indexPath),
              let file = viewModel.files.first(where: { $0.id == fileID }) else {
            return
        }
        Task { await viewModel.handleItemTap(file, api: taskAPI) }
    }

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let offsetY = scrollView.contentOffset.y
        let contentHeight = scrollView.contentSize.height
        let frameHeight = scrollView.frame.size.height
        if offsetY > contentHeight - frameHeight - 120 {
            Task { await viewModel.loadMore(api: taskAPI) }
        }
    }
}

extension CloudStoragePickForTaskViewController: UITextFieldDelegate {
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        viewModel.updateSearchText(textField.text ?? "")
        textField.resignFirstResponder()
        Task { await viewModel.refresh(api: taskAPI) }
        return true
    }
}

/// 云盘选择 cell。
private final class CloudPickCell: UICollectionViewCell {

    static let reuseIdentifier = "CloudPickCell"

    private let imageView = UIImageView()
    private let nameLabel = UILabel()
    private let selectionIconView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
    private let folderIconView = UIImageView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        contentView.backgroundColor = .white
        contentView.layer.cornerRadius = AppRadius.sm
        contentView.clipsToBounds = true

        imageView.contentMode = .scaleAspectFill
        imageView.clipsToBounds = true

        folderIconView.image = UIImage(systemName: "folder.fill")
        folderIconView.tintColor = AppColor.primary
        folderIconView.contentMode = .scaleAspectFit

        nameLabel.font = .app(.caption)
        nameLabel.textColor = AppColor.textPrimary
        nameLabel.numberOfLines = 2
        nameLabel.textAlignment = .center

        selectionIconView.tintColor = AppColor.primary
        selectionIconView.contentMode = .scaleAspectFit
        selectionIconView.isHidden = true

        contentView.addSubview(imageView)
        contentView.addSubview(folderIconView)
        contentView.addSubview(nameLabel)
        contentView.addSubview(selectionIconView)

        imageView.snp.makeConstraints { make in
            make.top.leading.trailing.equalToSuperview()
            make.height.equalTo(contentView.snp.width)
        }
        folderIconView.snp.makeConstraints { make in
            make.center.equalTo(imageView)
            make.width.height.equalTo(36)
        }
        nameLabel.snp.makeConstraints { make in
            make.top.equalTo(imageView.snp.bottom).offset(AppSpacing.xxs)
            make.leading.trailing.bottom.equalToSuperview().inset(AppSpacing.xxs)
        }
        selectionIconView.snp.makeConstraints { make in
            make.top.trailing.equalToSuperview().inset(AppSpacing.xxs)
            make.width.height.equalTo(20)
        }
    }

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

    override func prepareForReuse() {
        super.prepareForReuse()
        imageView.kf.cancelDownloadTask()
        imageView.image = nil
        folderIconView.isHidden = true
        selectionIconView.isHidden = true
        contentView.alpha = 1
    }

    func apply(file: CloudFile, isSelected: Bool, isImported: Bool, isGridMode: Bool) {
        nameLabel.text = file.name
        contentView.layer.borderWidth = isSelected ? 2 : 0
        contentView.layer.borderColor = AppColor.primary.cgColor
        selectionIconView.isHidden = !isSelected

        if isGridMode {
            imageView.snp.remakeConstraints { make in
                make.top.leading.trailing.equalToSuperview()
                make.height.equalTo(imageView.snp.width)
            }
            nameLabel.textAlignment = .center
            nameLabel.numberOfLines = 2
            nameLabel.snp.remakeConstraints { make in
                make.top.equalTo(imageView.snp.bottom).offset(AppSpacing.xxs)
                make.leading.trailing.bottom.equalToSuperview().inset(AppSpacing.xxs)
            }
        } else {
            imageView.snp.remakeConstraints { make in
                make.top.bottom.leading.equalToSuperview()
                make.width.equalTo(imageView.snp.height)
            }
            nameLabel.textAlignment = .left
            nameLabel.numberOfLines = 2
            nameLabel.snp.remakeConstraints { make in
                make.leading.equalTo(imageView.snp.trailing).offset(AppSpacing.sm)
                make.trailing.equalToSuperview().inset(AppSpacing.sm)
                make.centerY.equalToSuperview()
            }
        }

        if file.isFolder {
            contentView.alpha = 1
            imageView.image = nil
            folderIconView.isHidden = false
            return
        }
        folderIconView.isHidden = true
        let preview = file.coverUrl.isEmpty ? file.fileUrl : file.coverUrl
        if let url = URL(string: preview), !preview.isEmpty {
            imageView.kf.setImage(with: url)
        } else {
            imageView.image = UIImage(systemName: file.isVideo ? "video" : "photo")
            imageView.tintColor = AppColor.textTertiary
        }
        if isImported {
            contentView.alpha = 0.5
        } else {
            contentView.alpha = 1
        }
    }
}
