//
//  PermissionDropdownViewController.swift
//  suixinkan
//

import SnapKit
import UIKit

/// 权限申请下拉菜单的展示模式。
enum PermissionDropdownMode {
    case roles([RoleOption])
    case scenics([ScenicOption], isLoading: Bool)
}

/// 锚定在表单选择框下方的 Android 风格权限下拉菜单。
final class PermissionDropdownViewController: UIViewController, UITableViewDelegate, UITextFieldDelegate {

    private enum Section { case main }

    fileprivate enum Item: Hashable {
        case role(RoleOption)
        case scenic(ScenicOption)
        case loading
        case empty(String)
    }

    var onDismiss: (() -> Void)?
    var onRoleSelect: ((RoleOption) -> Void)?
    var onScenicToggle: ((ScenicOption) -> Void)?
    var onSearchChange: ((String) -> Void)?

    private let anchorFrame: CGRect
    private var mode: PermissionDropdownMode
    private var allScenics: [ScenicOption] = []
    private var query = ""
    private let dismissControl = UIControl()
    private let cardView = UIView()
    private let searchContainer = UIView()
    private let searchField = UITextField()
    private let tableView = UITableView(frame: .zero, style: .plain)
    private var dataSource: UITableViewDiffableDataSource<Section, Item>!
    private var cardHeightConstraint: Constraint?

    /// 创建与指定选择框等宽的下拉菜单。
    init(anchor: UIView, mode: PermissionDropdownMode) {
        anchorFrame = anchor.convert(anchor.bounds, to: nil)
        self.mode = mode
        if case .scenics(let scenics, _) = mode {
            allScenics = scenics
        }
        super.init(nibName: nil, bundle: nil)
        modalPresentationStyle = .overFullScreen
        modalTransitionStyle = .crossDissolve
    }

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

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .clear
        dismissControl.backgroundColor = .clear
        dismissControl.addTarget(self, action: #selector(dismissTapped), for: .touchUpInside)

        cardView.backgroundColor = .white
        cardView.layer.cornerRadius = 4
        cardView.layer.shadowColor = UIColor.black.cgColor
        cardView.layer.shadowOpacity = 0.14
        cardView.layer.shadowRadius = 8
        cardView.layer.shadowOffset = CGSize(width: 0, height: 4)
        cardView.clipsToBounds = false

        searchContainer.backgroundColor = .white
        searchContainer.layer.cornerRadius = 8
        searchContainer.layer.borderWidth = 1
        searchContainer.layer.borderColor = PermissionApplyUITokens.selectorBorder.cgColor

        let searchIcon = UIImageView(image: UIImage(systemName: "magnifyingglass"))
        searchIcon.tintColor = AppColor.textTertiary
        searchIcon.contentMode = .scaleAspectFit
        searchField.placeholder = "搜索景区名称"
        searchField.font = .systemFont(ofSize: 14)
        searchField.textColor = PermissionApplyUITokens.text
        searchField.returnKeyType = .search
        searchField.clearButtonMode = .whileEditing
        searchField.delegate = self
        searchField.addTarget(self, action: #selector(searchChanged), for: .editingChanged)
        searchField.accessibilityLabel = "搜索景区名称"

        tableView.backgroundColor = .white
        tableView.separatorStyle = .none
        tableView.keyboardDismissMode = .onDrag
        tableView.rowHeight = UITableView.automaticDimension
        tableView.estimatedRowHeight = 52
        tableView.delegate = self
        tableView.register(PermissionDropdownCell.self, forCellReuseIdentifier: PermissionDropdownCell.reuseIdentifier)

        view.addSubview(dismissControl)
        view.addSubview(cardView)
        cardView.addSubview(searchContainer)
        searchContainer.addSubview(searchIcon)
        searchContainer.addSubview(searchField)
        cardView.addSubview(tableView)

        dismissControl.snp.makeConstraints { make in make.edges.equalToSuperview() }
        cardView.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(anchorFrame.minX)
            make.top.equalToSuperview().offset(anchorFrame.maxY + 4)
            make.width.equalTo(anchorFrame.width)
            cardHeightConstraint = make.height.equalTo(80).constraint
        }
        searchContainer.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(8)
            make.leading.trailing.equalToSuperview().inset(12)
            make.height.equalTo(38)
        }
        searchIcon.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(12)
            make.centerY.equalToSuperview()
            make.size.equalTo(18)
        }
        searchField.snp.makeConstraints { make in
            make.leading.equalTo(searchIcon.snp.trailing).offset(10)
            make.trailing.equalToSuperview().offset(-8)
            make.top.bottom.equalToSuperview()
        }
        tableView.snp.makeConstraints { make in
            make.leading.trailing.bottom.equalToSuperview()
            make.top.equalTo(searchContainer.snp.bottom).offset(4)
        }

        configureDataSource()
        applyMode(animated: false)
    }

    /// 刷新景区数据和加载状态，同时保留下拉菜单及搜索词。
    func updateScenics(_ scenics: [ScenicOption], isLoading: Bool) {
        allScenics = scenics
        mode = .scenics(scenics, isLoading: isLoading)
        guard isViewLoaded else { return }
        applyMode(animated: false)
    }

    private func configureDataSource() {
        dataSource = UITableViewDiffableDataSource<Section, Item>(tableView: tableView) {
            tableView, indexPath, item in
            guard let cell = tableView.dequeueReusableCell(
                withIdentifier: PermissionDropdownCell.reuseIdentifier,
                for: indexPath
            ) as? PermissionDropdownCell else { return UITableViewCell() }
            cell.apply(item: item)
            return cell
        }
    }

    private func applyMode(animated: Bool) {
        var items: [Item]
        switch mode {
        case .roles(let roles):
            searchContainer.isHidden = true
            tableView.snp.remakeConstraints { make in make.edges.equalToSuperview() }
            items = roles.map(Item.role)
            if items.isEmpty { items = [.empty("暂无可用角色")] }
        case .scenics(_, let isLoading):
            searchContainer.isHidden = isLoading
            if isLoading {
                tableView.snp.remakeConstraints { make in make.edges.equalToSuperview() }
                items = [.loading]
            } else {
                tableView.snp.remakeConstraints { make in
                    make.leading.trailing.bottom.equalToSuperview()
                    make.top.equalTo(searchContainer.snp.bottom).offset(4)
                }
                let filtered = filteredScenics()
                items = filtered.map(Item.scenic)
                if items.isEmpty {
                    items = [.empty(query.isEmpty ? "暂无可用景区" : "未找到相关景区")]
                }
            }
        }

        var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
        snapshot.appendSections([.main])
        snapshot.appendItems(items)
        let completion: () -> Void = { [weak self] in
            guard let self else { return }
            self.updateCardHeight(itemCount: items.count)
        }
        if animated {
            dataSource.apply(snapshot, animatingDifferences: true, completion: completion)
        } else {
            UIView.performWithoutAnimation {
                dataSource.apply(snapshot, animatingDifferences: false, completion: completion)
                tableView.layoutIfNeeded()
            }
        }
    }

    private func filteredScenics() -> [ScenicOption] {
        let value = query.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !value.isEmpty else { return allScenics }
        return allScenics.filter { $0.name.localizedCaseInsensitiveContains(value) }
    }

    private func updateCardHeight(itemCount: Int) {
        tableView.layoutIfNeeded()
        let hasSearch = !searchContainer.isHidden
        let searchHeight: CGFloat = hasSearch ? 58 : 0
        let estimatedListHeight = max(64, min(262, tableView.contentSize.height > 0 ? tableView.contentSize.height : CGFloat(itemCount) * 52))
        cardHeightConstraint?.update(offset: min(320, searchHeight + estimatedListHeight))
        view.layoutIfNeeded()
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: false)
        guard let item = dataSource.itemIdentifier(for: indexPath) else { return }
        switch item {
        case .role(let role):
            onRoleSelect?(role)
            dismissMenu(notify: false)
        case .scenic(let scenic):
            guard !scenic.isDisabled else { return }
            onScenicToggle?(scenic)
            if let index = allScenics.firstIndex(where: { $0.id == scenic.id }) {
                allScenics[index].isSelected.toggle()
            }
            mode = .scenics(allScenics, isLoading: false)
            applyMode(animated: false)
        case .loading, .empty:
            break
        }
    }

    @objc private func searchChanged() {
        query = searchField.text ?? ""
        onSearchChange?(query)
        applyMode(animated: false)
    }

    @objc private func dismissTapped() {
        dismissMenu(notify: true)
    }

    private func dismissMenu(notify: Bool) {
        searchField.resignFirstResponder()
        dismiss(animated: true) { [weak self] in
            if notify { self?.onDismiss?() }
        }
    }
}

/// 权限下拉菜单中的角色、景区、加载或空状态单元格。
private final class PermissionDropdownCell: UITableViewCell {

    static let reuseIdentifier = "PermissionDropdownCell"

    private let titleLabel = UILabel()
    private let detailLabel = UILabel()
    private let checkCircle = UIView()
    private let checkImage = UIImageView(image: UIImage(systemName: "checkmark"))
    private let activityIndicator = UIActivityIndicatorView(style: .medium)

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        backgroundColor = .white
        selectionStyle = .none
        titleLabel.font = .systemFont(ofSize: 14)
        titleLabel.textColor = PermissionApplyUITokens.text
        titleLabel.numberOfLines = 1
        detailLabel.font = .systemFont(ofSize: 12)
        detailLabel.textColor = PermissionApplyUITokens.placeholder
        detailLabel.numberOfLines = 0
        checkCircle.frame = CGRect(x: 0, y: 0, width: 20, height: 20)
        checkCircle.layer.cornerRadius = 10
        checkImage.tintColor = .white
        checkImage.contentMode = .scaleAspectFit
        activityIndicator.color = PermissionApplyUITokens.selectedBlue

        [titleLabel, detailLabel, activityIndicator].forEach(contentView.addSubview)
        accessoryView = checkCircle
        checkCircle.addSubview(checkImage)
        titleLabel.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(12)
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-12)
        }
        detailLabel.snp.makeConstraints { make in
            make.top.equalTo(titleLabel.snp.bottom).offset(4)
            make.leading.equalTo(titleLabel)
            make.trailing.equalToSuperview().offset(-12)
            make.bottom.equalToSuperview().offset(-10)
        }
        checkImage.snp.makeConstraints { make in make.center.equalToSuperview(); make.size.equalTo(14) }
        activityIndicator.snp.makeConstraints { make in make.center.equalToSuperview() }
        contentView.snp.makeConstraints { make in make.height.greaterThanOrEqualTo(48) }
    }

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

    func apply(item: PermissionDropdownViewController.Item) {
        activityIndicator.stopAnimating()
        titleLabel.textAlignment = .left
        titleLabel.font = .systemFont(ofSize: 14)
        detailLabel.isHidden = true
        checkCircle.isHidden = true
        isUserInteractionEnabled = true
        switch item {
        case .role(let role):
            titleLabel.text = role.name
            titleLabel.font = .systemFont(ofSize: 14, weight: .medium)
            titleLabel.textColor = PermissionApplyUITokens.text
            detailLabel.text = role.description
            detailLabel.isHidden = role.description.isEmpty
            checkCircle.isHidden = false
            checkCircle.backgroundColor = role.isSelected
                ? PermissionApplyUITokens.selectedBlue : UIColor(hex: 0xE5E7EB)
            checkImage.isHidden = !role.isSelected
        case .scenic(let scenic):
            titleLabel.text = scenic.name
            titleLabel.textColor = scenic.isDisabled ? AppColor.textTertiary : PermissionApplyUITokens.text
            checkCircle.isHidden = false
            checkCircle.backgroundColor = scenic.isDisabled && scenic.isSelected
                ? AppColor.textTertiary
                : (scenic.isSelected ? PermissionApplyUITokens.selectedBlue : UIColor(hex: 0xE5E7EB))
            checkImage.isHidden = !scenic.isSelected
            isUserInteractionEnabled = !scenic.isDisabled
        case .loading:
            titleLabel.text = nil
            activityIndicator.startAnimating()
            isUserInteractionEnabled = false
        case .empty(let message):
            titleLabel.text = message
            titleLabel.textAlignment = .center
            titleLabel.textColor = AppColor.textTertiary
            isUserInteractionEnabled = false
        }
        if detailLabel.isHidden {
            titleLabel.snp.remakeConstraints { make in
                make.leading.equalToSuperview().offset(16)
                make.trailing.equalToSuperview().offset(-12)
                make.centerY.equalToSuperview()
                make.top.greaterThanOrEqualToSuperview().offset(12)
                make.bottom.lessThanOrEqualToSuperview().offset(-12)
            }
        } else {
            titleLabel.snp.remakeConstraints { make in
                make.top.equalToSuperview().offset(10)
                make.leading.equalToSuperview().offset(16)
                make.trailing.equalToSuperview().offset(-12)
            }
        }
        accessibilityLabel = [titleLabel.text, detailLabel.isHidden ? nil : detailLabel.text]
            .compactMap { $0 }.joined(separator: "，")
    }
}
