//
//  OrdersViewController.swift
//  suixinkan
//

import CoreLocation
import SnapKit
import UIKit

/// 订单 Tab 根页面，按角色分流摄影师/景区管理员/店铺管理员。
final class OrdersViewController: BaseViewController, UITableViewDataSource, UITableViewDelegate {

    private let orderAPI = NetworkServices.shared.orderAPI
    private let orderListViewModel = OrderListViewModel()
    private let depositViewModel = DepositOrderListViewModel()

    private let filterBar = OrderFilterBarView()
    private let listView = OrderListView()

    private var hasInitialized = false
    private var isStoreMode: Bool { AppStore.shared.session.currentAppRole == .storeAdmin }
    private var pendingOrderSourceNumber: String?
    private weak var orderSourcePicker: OrderSourcePickerViewController?
    private var pendingGiftOrderNumber: String?
    private var isFetchingMultiVerifySpots = false
    private let locationProvider: any LocationProviding = LocationProvider.shared

    override func setupNavigationBar() {
        title = "订单"
    }

    override func setupUI() {
        view.addSubview(filterBar)
        view.addSubview(listView)
        listView.tableView.dataSource = self
        listView.tableView.delegate = self
        listView.tableView.register(OrderCardCell.self, forCellReuseIdentifier: OrderCardCell.reuseIdentifier)
        listView.tableView.register(DepositOrderCardCell.self, forCellReuseIdentifier: DepositOrderCardCell.reuseIdentifier)
    }

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

    override func bindActions() {
        orderListViewModel.onStateChange = { [weak self] in
            Task { @MainActor in
                self?.applyViewModel()
                self?.orderSourcePicker?.reloadFromViewModel()
            }
        }
        orderListViewModel.onShowMessage = { [weak self] message in
            Task { @MainActor in self?.showToast(message) }
        }
        orderListViewModel.onNavigateBindAcquirer = { [weak self] saleUserId in
            Task { @MainActor in self?.presentBindAcquirer(saleUserId: saleUserId) }
        }
        depositViewModel.onStateChange = { [weak self] in
            Task { @MainActor in self?.applyViewModel() }
        }
        depositViewModel.onShowMessage = { [weak self] message in
            Task { @MainActor in self?.showToast(message) }
        }

        filterBar.onSearchChanged = { [weak self] text in
            guard let self else { return }
            if self.isStoreMode {
                self.depositViewModel.onSearchTextChange(text, api: self.orderAPI)
            } else {
                self.orderListViewModel.onSearchTextChange(text)
            }
        }
        filterBar.onSearchSubmitted = { [weak self] in
            guard let self else { return }
            Task {
                if self.isStoreMode {
                    await self.depositViewModel.refreshOrderList(api: self.orderAPI)
                } else {
                    await self.orderListViewModel.refreshOrderList(api: self.orderAPI)
                }
            }
        }
        filterBar.onFilterSelected = { [weak self] tab, rTab in
            guard let self else { return }
            Task {
                if self.isStoreMode {
                    self.depositViewModel.onFilterChange(tab: tab)
                    await self.depositViewModel.refreshOrderList(api: self.orderAPI)
                } else {
                    self.orderListViewModel.onFilterChange(orderStatus: tab, isRefined: rTab)
                    await self.orderListViewModel.refreshOrderList(api: self.orderAPI)
                }
            }
        }
        filterBar.onDateRangeTap = { [weak self] in
            self?.presentDateRangeSheet()
        }
        listView.onRefresh = { [weak self] in
            guard let self else { return }
            Task {
                if self.isStoreMode {
                    await self.depositViewModel.refreshOrderList(api: self.orderAPI)
                } else {
                    await self.orderListViewModel.refreshOrderList(api: self.orderAPI)
                }
            }
        }
        listView.onLoadMore = { [weak self] index in
            guard let self else { return }
            Task {
                if self.isStoreMode {
                    guard self.depositViewModel.shouldLoadMore(at: index) else { return }
                    await self.depositViewModel.loadMore(api: self.orderAPI)
                } else {
                    guard self.orderListViewModel.shouldLoadMore(at: index) else { return }
                    await self.orderListViewModel.loadMore(api: self.orderAPI)
                }
            }
        }
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        guard !hasInitialized else { return }
        hasInitialized = true
        Task { await initializeList() }
    }

    private func initializeList() async {
        if isStoreMode {
            await depositViewModel.refreshOrderList(api: orderAPI)
        } else {
            await orderListViewModel.refreshOrderList(api: orderAPI)
        }
    }

    private func applyViewModel() {
        if isStoreMode {
            filterBar.configure(
                isStoreMode: true,
                filterLabel: depositViewModel.filterLabel,
                dateRangeText: dateRangeText(start: depositViewModel.startTime, end: depositViewModel.endTime),
                searchText: depositViewModel.searchText
            )
            listView.apply(
                isRefreshing: depositViewModel.isRefreshing,
                canLoadMore: depositViewModel.canLoadMore,
                isEmpty: depositViewModel.orderList.isEmpty,
                isLoading: depositViewModel.isRefreshing && depositViewModel.orderList.isEmpty,
                isLoadingMore: depositViewModel.isLoadingMore
            )
            if let response = depositViewModel.writeOffResponse {
                depositViewModel.dismissWriteOffDialog()
                WriteOffResultAlertController.present(from: self, response: response)
            }
        } else {
            filterBar.configure(
                isStoreMode: false,
                filterLabel: orderListViewModel.filterLabel,
                dateRangeText: dateRangeText(start: orderListViewModel.startTime, end: orderListViewModel.endTime),
                searchText: orderListViewModel.searchText
            )
            listView.apply(
                isRefreshing: orderListViewModel.isRefreshing,
                canLoadMore: orderListViewModel.canLoadMore,
                isEmpty: orderListViewModel.orderList.isEmpty,
                isLoading: orderListViewModel.isRefreshing && orderListViewModel.orderList.isEmpty,
                isLoadingMore: orderListViewModel.isLoadingMore
            )
            if let response = orderListViewModel.signInResponse {
                orderListViewModel.clearSignInResponse()
                OrderSignInAlertController.present(from: self, response: response)
            }
            if let response = orderListViewModel.writeOffResponse {
                orderListViewModel.clearWriteOffResponse()
                WriteOffResultAlertController.present(from: self, response: response)
            }
            if orderListViewModel.multiVerifyPendingData != nil,
               orderListViewModel.multiVerifyScenicSpotList.isEmpty,
               !isFetchingMultiVerifySpots {
                Task { await self.fetchMultiVerifySpotsIfNeeded() }
            }
            if !orderListViewModel.multiVerifyScenicSpotList.isEmpty {
                presentMultiVerifySheet()
            }
        }
        listView.tableView.reloadData()
    }

    private func dateRangeText(start: Date?, end: Date?) -> String {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        if let start, let end {
            return "\(formatter.string(from: start))-\(formatter.string(from: end))"
        }
        return "时间筛选"
    }

    private func presentDateRangeSheet() {
        let start = isStoreMode ? depositViewModel.startTime : orderListViewModel.startTime
        let end = isStoreMode ? depositViewModel.endTime : orderListViewModel.endTime
        let controller = DateRangePickerViewController(rangeStart: start, rangeEnd: end)
        controller.onShortcutSelected = { [weak self, weak controller] shortcut in
            guard let self else { return }
            let range = self.resolveShortcutRange(shortcut)
            Task {
                if self.isStoreMode {
                    self.depositViewModel.onDateRangeSelected(start: range.start, end: range.end)
                    await self.depositViewModel.refreshOrderList(api: self.orderAPI)
                } else {
                    self.orderListViewModel.onDateRangeSelected(start: range.start, end: range.end)
                    await self.orderListViewModel.refreshOrderList(api: self.orderAPI)
                }
                controller?.dismiss(animated: true)
            }
        }
        controller.onRangeSelected = { [weak self, weak controller] start, end in
            guard let self else { return }
            Task {
                if self.isStoreMode {
                    self.depositViewModel.onDateRangeSelected(start: start, end: end)
                    await self.depositViewModel.refreshOrderList(api: self.orderAPI)
                } else {
                    self.orderListViewModel.onDateRangeSelected(start: start, end: end)
                    await self.orderListViewModel.refreshOrderList(api: self.orderAPI)
                }
                controller?.dismiss(animated: true)
            }
        }
        if let sheet = controller.sheetPresentationController {
            sheet.detents = [.medium(), .large()]
        }
        present(controller, animated: true)
    }

    private func resolveShortcutRange(_ shortcut: String) -> (start: Date?, end: Date?) {
        let calendar = Calendar.current
        let today = calendar.startOfDay(for: Date())
        switch shortcut {
        case StatisticsRangeShortcut.today.rawValue:
            return (today, today)
        case StatisticsRangeShortcut.yesterday.rawValue:
            let yesterday = calendar.date(byAdding: .day, value: -1, to: today)!
            return (yesterday, yesterday)
        case StatisticsRangeShortcut.last7Days.rawValue:
            let start = calendar.date(byAdding: .day, value: -6, to: today)!
            return (start, today)
        default:
            return (nil, nil)
        }
    }

    private func presentScanner(onResult: @escaping (String) -> Void) {
        let scanner = QRCodeScannerViewController()
        scanner.onScanResult = onResult
        let nav = UINavigationController(rootViewController: scanner)
        nav.modalPresentationStyle = .fullScreen
        present(nav, animated: true)
    }

    private func presentBindAcquirer(saleUserId: Int) {
        dismiss(animated: true) { [weak self] in
            let controller = BindAcquirerViewController(saleUserId: saleUserId)
            self?.navigationController?.pushViewController(controller, animated: true)
        }
    }

    private func fetchMultiVerifySpotsIfNeeded() async {
        isFetchingMultiVerifySpots = true
        defer { isFetchingMultiVerifySpots = false }
        do {
            let coordinate = try await locationProvider.requestCoordinate()
            await orderListViewModel.fetchScenicSpotsAndShowSheet(
                lat: coordinate.latitude,
                lng: coordinate.longitude,
                api: orderAPI
            )
            applyViewModel()
        } catch {
            showToast(error.localizedDescription)
            orderListViewModel.clearMultiVerifyPending()
        }
    }

    private func presentMultiVerifySheet() {
        let spots = orderListViewModel.multiVerifyScenicSpotList
        guard !spots.isEmpty else { return }
        let controller = MultiVerifyScenicSpotViewController(
            spots: spots,
            selected: orderListViewModel.selectedMultiVerifySpot
        )
        controller.onConfirm = { [weak self] spot in
            guard let self else { return }
            self.orderListViewModel.onMultiVerifySpotSelected(spot)
            Task { await self.orderListViewModel.onMultiVerifyConfirm(api: self.orderAPI) }
        }
        controller.onCancel = { [weak self] in
            self?.orderListViewModel.clearMultiVerifySheet()
        }
        let nav = UINavigationController(rootViewController: controller)
        if let sheet = nav.sheetPresentationController {
            sheet.detents = [.medium(), .large()]
        }
        present(nav, animated: true)
        orderListViewModel.clearMultiVerifySheet()
    }

    // MARK: - UITableView

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        isStoreMode ? depositViewModel.orderList.count : orderListViewModel.orderList.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if isStoreMode {
            let cell = tableView.dequeueReusableCell(withIdentifier: DepositOrderCardCell.reuseIdentifier, for: indexPath) as! DepositOrderCardCell
            let item = depositViewModel.orderList[indexPath.row]
            cell.configure(item: item, actions: makeDepositActions(for: item))
            listView.notifyLoadMoreIfNeeded(at: indexPath.row, shouldLoad: depositViewModel.shouldLoadMore(at: indexPath.row))
            return cell
        }

        let cell = tableView.dequeueReusableCell(withIdentifier: OrderCardCell.reuseIdentifier, for: indexPath) as! OrderCardCell
        let order = orderListViewModel.orderList[indexPath.row]
        let source = orderListViewModel.orderSourceSelection(for: order)
        cell.configure(
            order: order,
            hideWriteActions: orderListViewModel.isScenicAdminReadOnly,
            actions: makeOrderActions(for: order),
            showOrderSource: orderListViewModel.shouldShowOrderSource(for: order),
            sourceSelection: source
        )
        listView.notifyLoadMoreIfNeeded(at: indexPath.row, shouldLoad: orderListViewModel.shouldLoadMore(at: indexPath.row))
        return cell
    }

    private func makeOrderActions(for order: OrderEntity) -> OrderCardActions {
        var actions = OrderCardActions()
        actions.onRefund = { [weak self] in
            guard let self else { return }
            OrderRefundAlertController.present(from: self, order: order) { request in
                Task { await self.orderListViewModel.refundOrder(request, api: self.orderAPI) }
            }
        }
        actions.onVerify = { [weak self] in
            self?.presentScanner { result in
                Task { await self?.orderListViewModel.processScanResult(result, api: self?.orderAPI ?? NetworkServices.shared.orderAPI) }
            }
        }
        actions.onUploadTask = { [weak self] in
            self?.showToast("上传任务待接入")
        }
        actions.onCancel = { [weak self] in
            guard let self else { return }
            Task { await self.orderListViewModel.cancelOrder(orderNumber: order.orderNumber, api: self.orderAPI) }
        }
        actions.onCallPhone = {
            guard let url = URL(string: "tel://\(order.phone)") else { return }
            UIApplication.shared.open(url)
        }
        actions.onRefinedChanged = { [weak self] value in
            guard let self else { return }
            Task { await self.orderListViewModel.updateRefined(orderNumber: order.orderNumber, isRefined: value, api: self.orderAPI) }
        }
        actions.onHistoricalPhoto = { [weak self] in
            let controller = HistoricalShootingInfoViewController(orderNumber: order.orderNumber)
            self?.navigationController?.pushViewController(controller, animated: true)
        }
        actions.onOrderSourceTap = { [weak self] in
            self?.presentOrderSourcePicker(for: order)
        }
        actions.onOrderSourceImageTap = { [weak self] images, index in
            self?.presentImagePreview(imageURLs: images, startIndex: index)
        }
        if let travel = order.photoTravel, travel.canGiftRetouch {
            actions.onSendGift = { [weak self] in
                guard let self else { return }
                self.pendingGiftOrderNumber = order.orderNumber
                SendGiftAlertController.present(
                    from: self,
                    photoNum: travel.retouchGiftPhotoNum,
                    videoNum: travel.retouchGiftVideoNum
                ) { photo, video in
                    Task {
                        await self.orderListViewModel.sendGift(
                            orderNumber: order.orderNumber,
                            photoNum: photo,
                            videoNum: video,
                            api: self.orderAPI
                        )
                    }
                }
            }
        }
        return actions
    }

    private func makeDepositActions(for item: StoreOrderItem) -> DepositOrderCardActions {
        var actions = DepositOrderCardActions()
        actions.onRefund = { [weak self] in
            guard let self else { return }
            DepositOrderRefundAlertController.present(
                from: self,
                orderNumber: item.orderNumber,
                amount: item.actualPayAmount,
                refundType: 1
            ) { refundType, amount, reason in
                Task {
                    await self.depositViewModel.requestRefund(
                        orderNumber: item.orderNumber,
                        refundType: refundType,
                        refundAmount: amount,
                        refundReason: reason,
                        api: self.orderAPI
                    )
                }
            }
        }
        actions.onPartialRefund = { [weak self] in
            guard let self else { return }
            DepositOrderRefundAlertController.present(
                from: self,
                orderNumber: item.orderNumber,
                amount: item.actualPayAmount,
                refundType: 3
            ) { refundType, amount, reason in
                Task {
                    await self.depositViewModel.requestRefund(
                        orderNumber: item.orderNumber,
                        refundType: refundType,
                        refundAmount: amount,
                        refundReason: reason,
                        api: self.orderAPI
                    )
                }
            }
        }
        actions.onVerify = { [weak self] in
            self?.presentScanner { result in
                Task { await self?.depositViewModel.processScanResult(result, api: self?.orderAPI ?? NetworkServices.shared.orderAPI) }
            }
        }
        actions.onCallPhone = {
            guard let url = URL(string: "tel://\(item.phone)") else { return }
            UIApplication.shared.open(url)
        }
        actions.onTap = { [weak self] in
            guard let self else { return }
            guard self.depositViewModel.canOpenDetail(for: item) else {
                self.showToast("该订单类型暂无详情")
                return
            }
            let controller = DepositOrderDetailViewController(orderNumber: item.orderNumber)
            self.navigationController?.pushViewController(controller, animated: true)
        }
        return actions
    }

    private func presentOrderSourcePicker(for order: OrderEntity) {
        pendingOrderSourceNumber = order.orderNumber
        Task {
            await orderListViewModel.onOrderSourceSheetOpen(api: orderAPI)
            await MainActor.run { [weak self] in
                guard let self else { return }
                let controller = OrderSourcePickerViewController(
                    orderNumber: order.orderNumber,
                    viewModel: self.orderListViewModel,
                    referralOrder: order.referralOrder,
                    loadLeads: { [weak self] person in
                        guard let self else { return }
                        await self.orderListViewModel.loadOrderSourceLeads(person: person, api: self.orderAPI)
                    },
                    onLeadBound: { [weak self] selection in
                        guard let self, let orderNumber = self.pendingOrderSourceNumber else { return }
                        self.dismiss(animated: true) {
                            self.orderSourcePicker = nil
                        }
                        Task {
                            await self.orderListViewModel.bindOrderSource(
                                orderNumber: orderNumber,
                                selection: selection,
                                api: self.orderAPI
                            )
                        }
                    },
                    onCallPhone: { [weak self] phone in
                        self?.callPhone(phone)
                    }
                )
                self.orderSourcePicker = controller
                let nav = UINavigationController(rootViewController: controller)
                if let sheet = nav.sheetPresentationController {
                    sheet.prefersGrabberVisible = true
                    if #available(iOS 16.0, *) {
                        sheet.detents = [
                            .custom(identifier: .init("orderSource")) { context in
                                context.maximumDetentValue * 0.82
                            },
                            .large(),
                        ]
                        sheet.selectedDetentIdentifier = .init("orderSource")
                    } else {
                        sheet.detents = [.large()]
                    }
                }
                self.present(nav, animated: true)
            }
        }
    }

    private func callPhone(_ phone: String) {
        let trimmed = phone.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !trimmed.isEmpty, let url = URL(string: "tel://\(trimmed)") else { return }
        UIApplication.shared.open(url)
    }
}
