//
//  WalletViewController.swift
//  suixinkan
//

import SnapKit
import UIKit

/// 我的钱包页面，对齐 Android 钱包首页的余额卡、提现记录、收益明细和提现入口。
final class WalletViewController: BaseViewController, UITableViewDelegate {
    private enum Section {
        case main
    }

    private enum Item: Hashable {
        case withdraw(WalletWithdrawItem)
        case transactionHeader(EarningDetailGroup)
        case transaction(EarningDetailItem)
    }

    private let viewModel: WalletViewModel
    private let walletAPI: any WalletPageServing
    private let profileAPI: any WalletProfileServing

    private let summaryCard = WalletSummaryCardView()
    private let contentCard = UIView()
    private let tabStack = UIStackView()
    private let withdrawTabButton = UIButton(type: .system)
    private let transactionTabButton = UIButton(type: .system)
    private let filterPanel = WalletFilterPanelView()
    private let tableView = UITableView(frame: .zero, style: .plain)
    private let refreshControl = UIRefreshControl()
    private let bottomBar = UIView()
    private let withdrawButton = AppButton(title: "提现到银行卡")

    private var dataSource: UITableViewDiffableDataSource<Section, Item>!
    private var lastShownMessage: String?

    /// 初始化钱包页面。
    init(
        viewModel: WalletViewModel = WalletViewModel(),
        walletAPI: any WalletPageServing = NetworkServices.shared.walletAPI,
        profileAPI: any WalletProfileServing = NetworkServices.shared.profileAPI
    ) {
        self.viewModel = viewModel
        self.walletAPI = walletAPI
        self.profileAPI = profileAPI
        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 = UIColor(hex: 0xF5F6F8)
        contentCard.backgroundColor = .white
        contentCard.layer.cornerRadius = 16
        contentCard.clipsToBounds = true

        tabStack.axis = .horizontal
        tabStack.distribution = .fillEqually
        [withdrawTabButton, transactionTabButton].forEach {
            $0.titleLabel?.font = .systemFont(ofSize: 16, weight: .semibold)
            $0.setTitleColor(UIColor(hex: 0x666666), for: .normal)
            tabStack.addArrangedSubview($0)
        }
        withdrawTabButton.setTitle("提现记录", for: .normal)
        transactionTabButton.setTitle("收益明细", for: .normal)

        tableView.backgroundColor = .white
        tableView.separatorStyle = .none
        tableView.delegate = self
        tableView.rowHeight = UITableView.automaticDimension
        tableView.estimatedRowHeight = 120
        tableView.refreshControl = refreshControl
        tableView.register(WalletWithdrawRecordCell.self, forCellReuseIdentifier: WalletWithdrawRecordCell.reuseIdentifier)
        tableView.register(WalletTransactionHeaderCell.self, forCellReuseIdentifier: WalletTransactionHeaderCell.reuseIdentifier)
        tableView.register(WalletTransactionRecordCell.self, forCellReuseIdentifier: WalletTransactionRecordCell.reuseIdentifier)

        bottomBar.backgroundColor = .white

        view.addSubview(summaryCard)
        view.addSubview(contentCard)
        contentCard.addSubview(tabStack)
        contentCard.addSubview(filterPanel)
        contentCard.addSubview(tableView)
        view.addSubview(bottomBar)
        bottomBar.addSubview(withdrawButton)

        configureDataSource()
    }

    override func setupConstraints() {
        summaryCard.snp.makeConstraints { make in
            make.top.equalTo(view.safeAreaLayoutGuide).offset(16)
            make.leading.trailing.equalToSuperview().inset(16)
        }
        bottomBar.snp.makeConstraints { make in
            make.leading.trailing.bottom.equalToSuperview()
        }
        withdrawButton.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(16)
            make.leading.trailing.equalToSuperview().inset(16)
            make.bottom.equalTo(view.safeAreaLayoutGuide).inset(22)
        }
        contentCard.snp.makeConstraints { make in
            make.top.equalTo(summaryCard.snp.bottom).offset(16)
            make.leading.trailing.equalToSuperview().inset(16)
            make.bottom.equalTo(bottomBar.snp.top).offset(-16)
        }
        tabStack.snp.makeConstraints { make in
            make.top.leading.trailing.equalToSuperview()
            make.height.equalTo(50)
        }
        filterPanel.snp.makeConstraints { make in
            make.top.equalTo(tabStack.snp.bottom)
            make.leading.trailing.equalToSuperview().inset(16)
        }
        tableView.snp.makeConstraints { make in
            make.top.equalTo(filterPanel.snp.bottom).offset(4)
            make.leading.trailing.bottom.equalToSuperview()
        }
    }

    override func bindActions() {
        viewModel.onStateChange = { [weak self] in
            Task { @MainActor in
                self?.applyState()
            }
        }
        summaryCard.onPointsTap = { [weak self] in
            self?.openPointsRedemption()
        }
        withdrawTabButton.addTarget(self, action: #selector(withdrawTabTapped), for: .touchUpInside)
        transactionTabButton.addTarget(self, action: #selector(transactionTabTapped), for: .touchUpInside)
        filterPanel.onFilterTap = { [weak self] in
            self?.presentFilterMenu()
        }
        refreshControl.addTarget(self, action: #selector(refreshPulled), for: .valueChanged)
        withdrawButton.addTarget(self, action: #selector(withdrawTapped), for: .touchUpInside)

        Task { await viewModel.loadInitial(api: walletAPI) }
    }

    private func configureDataSource() {
        dataSource = UITableViewDiffableDataSource<Section, Item>(tableView: tableView) { tableView, indexPath, item in
            switch item {
            case .withdraw(let record):
                let cell = tableView.dequeueReusableCell(
                    withIdentifier: WalletWithdrawRecordCell.reuseIdentifier,
                    for: indexPath
                ) as? WalletWithdrawRecordCell
                cell?.apply(record)
                return cell ?? UITableViewCell()
            case .transactionHeader(let group):
                let cell = tableView.dequeueReusableCell(
                    withIdentifier: WalletTransactionHeaderCell.reuseIdentifier,
                    for: indexPath
                ) as? WalletTransactionHeaderCell
                cell?.apply(group)
                return cell ?? UITableViewCell()
            case .transaction(let record):
                let cell = tableView.dequeueReusableCell(
                    withIdentifier: WalletTransactionRecordCell.reuseIdentifier,
                    for: indexPath
                ) as? WalletTransactionRecordCell
                cell?.apply(record)
                return cell ?? UITableViewCell()
            }
        }
    }

    private func applyState() {
        summaryCard.apply(
            withdrawable: viewModel.summary?.amountWithdrawable,
            total: viewModel.summary?.amountTotal,
            balance: viewModel.summary?.amountCurrentBalance,
            points: viewModel.availablePoints
        )
        applyTabAppearance()
        filterPanel.isHidden = viewModel.selectedTab != .transaction
        filterPanel.apply(filter: viewModel.filter, totalIncome: viewModel.totalIncomeLabel, totalPoints: viewModel.totalPointsLabel)
        refreshControl.endRefreshing()
        applySnapshot()
        if let message = viewModel.errorMessage, message != lastShownMessage {
            lastShownMessage = message
            showToast(message)
        }
    }

    private func applyTabAppearance() {
        let selectedColor = UIColor(hex: 0x1677FF)
        let normalColor = UIColor(hex: 0x666666)
        withdrawTabButton.setTitleColor(viewModel.selectedTab == .withdraw ? selectedColor : normalColor, for: .normal)
        transactionTabButton.setTitleColor(viewModel.selectedTab == .transaction ? selectedColor : normalColor, for: .normal)
        withdrawTabButton.titleLabel?.font = .systemFont(ofSize: 16, weight: viewModel.selectedTab == .withdraw ? .semibold : .regular)
        transactionTabButton.titleLabel?.font = .systemFont(ofSize: 16, weight: viewModel.selectedTab == .transaction ? .semibold : .regular)
    }

    private func applySnapshot() {
        var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
        snapshot.appendSections([.main])
        if viewModel.selectedTab == .withdraw {
            snapshot.appendItems(viewModel.withdrawRecords.map(Item.withdraw), toSection: .main)
        } else {
            let items = viewModel.transactionEntries.map { entry -> Item in
                switch entry {
                case .header(let group): .transactionHeader(group)
                case .item(let item): .transaction(item)
                }
            }
            snapshot.appendItems(items, toSection: .main)
        }
        dataSource.apply(snapshot, animatingDifferences: true)
        updateEmptyState()
    }

    private func updateEmptyState() {
        let emptyText: String?
        if viewModel.selectedTab == .withdraw, viewModel.withdrawRecords.isEmpty, !viewModel.withdrawLoading {
            emptyText = "暂无提现记录"
        } else if viewModel.selectedTab == .transaction, viewModel.transactionEntries.isEmpty, !viewModel.transactionLoading {
            emptyText = "暂无收益明细"
        } else {
            emptyText = nil
        }
        guard let emptyText else {
            tableView.backgroundView = nil
            return
        }
        let label = UILabel()
        label.text = emptyText
        label.textColor = UIColor(hex: 0xB3B8C2)
        label.font = .systemFont(ofSize: 14)
        label.textAlignment = .center
        tableView.backgroundView = label
    }

    private func presentFilterMenu() {
        let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
        WalletFilter.allCases.forEach { filter in
            alert.addAction(UIAlertAction(title: filter.title, style: .default) { [weak self] _ in
                guard let self else { return }
                Task { await self.viewModel.selectFilter(filter, api: self.walletAPI) }
            })
        }
        alert.addAction(UIAlertAction(title: "取消", style: .cancel))
        present(alert, animated: true)
    }

    private func openPointsRedemption() {
        navigationController?.pushViewController(PointsRedemptionViewController(), animated: true)
    }

    @objc private func withdrawTabTapped() {
        Task { await viewModel.selectTab(.withdraw, api: walletAPI) }
    }

    @objc private func transactionTabTapped() {
        Task { await viewModel.selectTab(.transaction, api: walletAPI) }
    }

    @objc private func refreshPulled() {
        Task {
            switch viewModel.selectedTab {
            case .withdraw:
                await viewModel.refreshSummary(api: walletAPI)
                await viewModel.refreshWithdraw(api: walletAPI)
                await viewModel.refreshPoints(api: walletAPI)
            case .transaction:
                await viewModel.refreshTransaction(api: walletAPI)
            }
        }
    }

    @objc private func withdrawTapped() {
        Task {
            showLoading()
            do {
                let destination = try await viewModel.resolveWithdrawDestination(profileAPI: profileAPI)
                hideLoading()
                route(to: destination)
            } catch {
                hideLoading()
                showToast(error.localizedDescription)
            }
        }
    }

    private func route(to destination: WalletWithdrawDestination) {
        switch destination {
        case .realNameAuth:
            navigationController?.pushViewController(RealNameAuthViewController(), animated: true)
        case .realNameAudit(let info):
            showToast("实名认证不通过，请重新提交")
            navigationController?.pushViewController(RealNameAuthAuditViewController(info: info), animated: true)
        case .realNamePending:
            showToast("实名认证审核中，请审核通过后再试")
        case .withdrawalSettings:
            navigationController?.pushViewController(WithdrawalSettingsViewController(), animated: true)
        case .withdrawalAudit(let bankCard):
            showToast("银行卡审核不通过，请重新提交")
            navigationController?.pushViewController(WithdrawalSettingsAuditViewController(bankCard: bankCard), animated: true)
        case .bankCardPending:
            showToast("银行卡审核中，请审核通过后再试")
        case .withdraw:
            let controller = WithdrawViewController()
            controller.onSubmitSuccess = { [weak self] in
                guard let self else { return }
                Task {
                    await self.viewModel.refreshSummary(api: self.walletAPI)
                    await self.viewModel.refreshWithdraw(api: self.walletAPI)
                }
            }
            navigationController?.pushViewController(controller, animated: true)
        }
    }

    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        Task {
            switch viewModel.selectedTab {
            case .withdraw:
                await viewModel.loadMoreWithdrawIfNeeded(currentIndex: indexPath.row, api: walletAPI)
            case .transaction:
                await viewModel.loadMoreTransactionIfNeeded(currentIndex: indexPath.row, api: walletAPI)
            }
        }
    }
}

/// 钱包顶部金额汇总卡片。
private final class WalletSummaryCardView: UIView {
    var onPointsTap: (() -> Void)?

    private let withdrawableTitle = UILabel()
    private let withdrawableLabel = UILabel()
    private let totalView = WalletSummaryMetricView()
    private let balanceView = WalletSummaryMetricView()
    private let pointsView = WalletSummaryMetricView(showsArrow: true)
    private let metricsStack = UIStackView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

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

    func apply(withdrawable: String?, total: String?, balance: String?, points: Int) {
        withdrawableLabel.text = WalletViewModel.formatAmount(withdrawable)
        totalView.apply(title: "累计金额", value: WalletViewModel.formatAmount(total))
        balanceView.apply(title: "当前余额", value: WalletViewModel.formatAmount(balance))
        pointsView.apply(title: "当前积分", value: "\(points)")
    }

    private func setupUI() {
        backgroundColor = UIColor(hex: 0x1677FF)
        layer.cornerRadius = 24
        clipsToBounds = true

        withdrawableTitle.text = "可提现金额"
        withdrawableTitle.textColor = UIColor.white.withAlphaComponent(0.8)
        withdrawableTitle.font = .systemFont(ofSize: 14)
        withdrawableTitle.textAlignment = .center

        withdrawableLabel.textColor = .white
        withdrawableLabel.font = .systemFont(ofSize: 36, weight: .bold)
        withdrawableLabel.textAlignment = .center
        withdrawableLabel.adjustsFontSizeToFitWidth = true
        withdrawableLabel.minimumScaleFactor = 0.7

        metricsStack.axis = .horizontal
        metricsStack.distribution = .fillEqually
        [totalView, balanceView, pointsView].forEach(metricsStack.addArrangedSubview)
        pointsView.addTarget(self, action: #selector(pointsTapped), for: .touchUpInside)

        addSubview(withdrawableTitle)
        addSubview(withdrawableLabel)
        addSubview(metricsStack)

        withdrawableTitle.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(16)
            make.leading.trailing.equalToSuperview().inset(24)
        }
        withdrawableLabel.snp.makeConstraints { make in
            make.top.equalTo(withdrawableTitle.snp.bottom).offset(4)
            make.leading.trailing.equalToSuperview().inset(24)
        }
        metricsStack.snp.makeConstraints { make in
            make.top.equalTo(withdrawableLabel.snp.bottom).offset(18)
            make.leading.trailing.equalToSuperview().inset(12)
            make.bottom.equalToSuperview().inset(16)
        }
    }

    @objc private func pointsTapped() {
        onPointsTap?()
    }
}

/// 钱包汇总卡片里的单项指标。
private final class WalletSummaryMetricView: UIControl {
    private let titleLabel = UILabel()
    private let valueLabel = UILabel()
    private let arrowLabel = UILabel()
    private let showsArrow: Bool

    init(showsArrow: Bool = false) {
        self.showsArrow = showsArrow
        super.init(frame: .zero)
        setupUI()
    }

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

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

    private func setupUI() {
        titleLabel.textColor = UIColor.white.withAlphaComponent(0.8)
        titleLabel.font = .systemFont(ofSize: 14)
        titleLabel.textAlignment = .center

        valueLabel.textColor = .white
        valueLabel.font = .systemFont(ofSize: 14, weight: .medium)
        valueLabel.textAlignment = .center
        valueLabel.adjustsFontSizeToFitWidth = true
        valueLabel.minimumScaleFactor = 0.75

        arrowLabel.text = showsArrow ? "›" : ""
        arrowLabel.textColor = .white
        arrowLabel.font = .systemFont(ofSize: 20, weight: .medium)

        let valueStack = UIStackView(arrangedSubviews: [valueLabel, arrowLabel])
        valueStack.axis = .horizontal
        valueStack.alignment = .center
        valueStack.spacing = 2
        valueStack.distribution = .fill

        addSubview(titleLabel)
        addSubview(valueStack)

        titleLabel.snp.makeConstraints { make in
            make.top.leading.trailing.equalToSuperview()
        }
        valueStack.snp.makeConstraints { make in
            make.top.equalTo(titleLabel.snp.bottom).offset(6)
            make.centerX.equalToSuperview()
            make.leading.greaterThanOrEqualToSuperview()
            make.trailing.lessThanOrEqualToSuperview()
            make.bottom.equalToSuperview()
        }
    }
}

/// 收益明细筛选和汇总面板。
private final class WalletFilterPanelView: UIView {
    var onFilterTap: (() -> Void)?

    private let filterButton = UIButton(type: .system)
    private let totalTitleLabel = UILabel()
    private let totalLabel = UILabel()
    private let pointsLabel = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

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

    func apply(filter: WalletFilter, totalIncome: String, totalPoints: Int) {
        filterButton.setTitle("\(filter.title)  ▾", for: .normal)
        totalLabel.text = totalIncome.isEmpty ? "¥ 0.00" : totalIncome
        pointsLabel.text = "积分+\(totalPoints)"
    }

    private func setupUI() {
        backgroundColor = UIColor(hex: 0xF6F6F6)
        layer.cornerRadius = 16
        clipsToBounds = true

        filterButton.setTitleColor(UIColor(hex: 0x111827), for: .normal)
        filterButton.titleLabel?.font = .systemFont(ofSize: 14)
        filterButton.contentHorizontalAlignment = .left
        filterButton.addTarget(self, action: #selector(filterTapped), for: .touchUpInside)

        totalTitleLabel.text = "总收益:"
        totalTitleLabel.font = .systemFont(ofSize: 14, weight: .medium)
        totalTitleLabel.textColor = .black

        totalLabel.font = .systemFont(ofSize: 14, weight: .medium)
        totalLabel.textColor = UIColor(hex: 0x0073FF)

        pointsLabel.font = .systemFont(ofSize: 14, weight: .medium)
        pointsLabel.textColor = UIColor(hex: 0xFF7B00)
        pointsLabel.textAlignment = .right

        addSubview(filterButton)
        addSubview(totalTitleLabel)
        addSubview(totalLabel)
        addSubview(pointsLabel)

        filterButton.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(8)
            make.leading.equalToSuperview().offset(16)
            make.width.lessThanOrEqualTo(150)
            make.height.equalTo(32)
        }
        totalTitleLabel.snp.makeConstraints { make in
            make.top.equalTo(filterButton.snp.bottom).offset(4)
            make.leading.equalToSuperview().offset(16)
            make.bottom.equalToSuperview().inset(12)
        }
        totalLabel.snp.makeConstraints { make in
            make.centerY.equalTo(totalTitleLabel)
            make.leading.equalTo(totalTitleLabel.snp.trailing).offset(8)
        }
        pointsLabel.snp.makeConstraints { make in
            make.centerY.equalTo(totalTitleLabel)
            make.leading.greaterThanOrEqualTo(totalLabel.snp.trailing).offset(8)
            make.trailing.equalToSuperview().inset(16)
        }
    }

    @objc private func filterTapped() {
        onFilterTap?()
    }
}
