//
//  OrderDialogControllers.swift
//  suixinkan
//

import SnapKit
import UIKit

/// 普通订单退款弹窗入口，对齐 Android `OrderRefundDialog`。
enum OrderRefundAlertController {
    static func present(
        from presenter: UIViewController,
        order: OrderEntity,
        onConfirm: @escaping (OrderRefundRequest) -> Void
    ) {
        let fullAmount = order.orderAmount.isEmpty ? order.actualPayAmount : order.orderAmount
        let dialog = OrderRefundDialogView(
            configuration: .photographerOrder(
                orderNumber: order.orderNumber,
                fullRefundAmount: fullAmount
            )
        )
        dialog.onMessage = { [weak presenter] message in
            (presenter as? BaseViewController)?.showToast(message)
        }
        dialog.onConfirm = { payload in
            onConfirm(
                OrderRefundRequest(
                    orderNumber: order.orderNumber,
                    refundType: payload.refundType,
                    refundAmount: payload.refundAmount,
                    refundReason: payload.refundReason
                )
            )
        }
        dialog.show(in: presenter.view)
    }
}

/// 店铺/定金订单退款弹窗入口，对齐 Android `DepositOrderRefundDialog`。
enum DepositOrderRefundAlertController {
    static func present(
        from presenter: UIViewController,
        orderNumber: String,
        amount: String,
        refundType: Int,
        onConfirm: @escaping (Int, String, String) -> Void
    ) {
        let dialog = OrderRefundDialogView(
            configuration: .storeOrder(
                orderNumber: orderNumber,
                actualPayAmount: amount,
                initialMode: OrderRefundMode(rawValue: refundType) ?? .full
            )
        )
        dialog.onMessage = { [weak presenter] message in
            (presenter as? BaseViewController)?.showToast(message)
        }
        dialog.onConfirm = { payload in
            onConfirm(payload.refundType, payload.refundAmount, payload.refundReason)
        }
        dialog.show(in: presenter.view)
    }
}

/// 退款方式，和 Android 常量 `1=全额退款、3=部分退款` 保持一致。
enum OrderRefundMode: Int {
    case full = 1
    case partial = 3
}

/// 退款弹窗校验场景。
enum OrderRefundDialogKind {
    case photographerOrder
    case storeOrder
}

/// 退款弹窗确认后的结构化结果。
struct OrderRefundDialogPayload: Equatable {
    let refundType: Int
    let refundAmount: String
    let refundReason: String
}

/// 退款弹窗校验失败信息。
struct OrderRefundDialogValidationError: Error, Equatable {
    let message: String
}

/// 退款弹窗输入校验与金额格式化逻辑，对齐 Android 两个退款弹窗。
enum OrderRefundDialogValidation {

    static func filterMoneyInput(_ text: String, maxLength: Int) -> String {
        var result = ""
        var hasDot = false
        var decimalCount = 0

        for character in text {
            guard result.count < maxLength else { break }
            if character.isNumber {
                if hasDot {
                    guard decimalCount < 2 else { continue }
                    decimalCount += 1
                }
                result.append(character)
            } else if character == ".", !hasDot {
                hasDot = true
                result.append(character)
            }
        }
        return result
    }

    static func validate(
        kind: OrderRefundDialogKind,
        mode: OrderRefundMode,
        amountText: String,
        reason: String,
        fullRefundAmount: String,
        maxRefundAmount: String
    ) -> Result<OrderRefundDialogPayload, OrderRefundDialogValidationError> {
        let trimmedReason = reason.trimmingCharacters(in: .whitespacesAndNewlines)
        switch kind {
        case .photographerOrder:
            return validatePhotographerOrder(
                mode: mode,
                amountText: amountText,
                reason: trimmedReason,
                fullRefundAmount: fullRefundAmount
            )
        case .storeOrder:
            return validateStoreOrder(
                mode: mode,
                amountText: amountText,
                reason: trimmedReason,
                maxRefundAmount: maxRefundAmount
            )
        }
    }

    private static func validatePhotographerOrder(
        mode: OrderRefundMode,
        amountText: String,
        reason: String,
        fullRefundAmount: String
    ) -> Result<OrderRefundDialogPayload, OrderRefundDialogValidationError> {
        guard !reason.isEmpty else {
            return .failure(OrderRefundDialogValidationError(message: "请输入退款原因"))
        }
        guard reason.count <= 255 else {
            return .failure(OrderRefundDialogValidationError(message: "退款原因最多255个字符"))
        }
        if mode == .partial, amountText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            return .failure(OrderRefundDialogValidationError(message: "请输入退款金额"))
        }
        let refundAmount = mode == .full ? fullRefundAmount : amountText
        return .success(
            OrderRefundDialogPayload(
                refundType: mode.rawValue,
                refundAmount: refundAmount,
                refundReason: reason
            )
        )
    }

    private static func validateStoreOrder(
        mode: OrderRefundMode,
        amountText: String,
        reason: String,
        maxRefundAmount: String
    ) -> Result<OrderRefundDialogPayload, OrderRefundDialogValidationError> {
        guard reason.count >= 5 else {
            return .failure(OrderRefundDialogValidationError(message: "退款原因至少5个字符"))
        }
        guard reason.count <= 255 else {
            return .failure(OrderRefundDialogValidationError(message: "退款原因最多255个字符"))
        }
        guard mode == .partial else {
            return .success(
                OrderRefundDialogPayload(
                    refundType: mode.rawValue,
                    refundAmount: "0",
                    refundReason: reason
                )
            )
        }
        let trimmedAmount = amountText.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !trimmedAmount.isEmpty else {
            return .failure(OrderRefundDialogValidationError(message: "请输入退款金额"))
        }
        guard let amount = Double(trimmedAmount), amount > 0 else {
            return .failure(OrderRefundDialogValidationError(message: "请输入有效的退款金额"))
        }
        let maxAmount = parseAmount(maxRefundAmount)
        guard maxAmount <= 0 || amount <= maxAmount else {
            return .failure(OrderRefundDialogValidationError(message: "退款金额不能大于实际支付金额"))
        }
        return .success(
            OrderRefundDialogPayload(
                refundType: mode.rawValue,
                refundAmount: String(format: "%.2f", amount),
                refundReason: reason
            )
        )
    }

    private static func parseAmount(_ text: String) -> Double {
        text
            .replacingOccurrences(of: ",", with: "")
            .replacingOccurrences(of: "¥", with: "")
            .trimmingCharacters(in: .whitespacesAndNewlines)
            .toDoubleOrZero
    }
}

private extension String {
    var toDoubleOrZero: Double {
        Double(self) ?? 0
    }
}

/// 自定义订单退款弹窗视图，对齐 Android `OrderRefundDialog` / `DepositOrderRefundDialog`。
final class OrderRefundDialogView: KeyboardAvoidingDialogView, UITextViewDelegate {

    /// 退款弹窗局部布局尺寸，保持内容紧凑但不牺牲基础点击区域。
    private enum Layout {
        static let sectionGap: CGFloat = AppSpacing.lg
        static let formGap: CGFloat = AppSpacing.md
        static let controlHeight: CGFloat = AppSpacing.minTouchTarget
        static let amountGroupHeight: CGFloat = 67
        static let remarkHeight: CGFloat = 88
        static let actionTop: CGFloat = 14
        static let bottomInset: CGFloat = AppSpacing.md
    }

    /// 退款弹窗展示与校验配置，用于区分普通订单和店铺/定金订单。
    struct Configuration {
        let kind: OrderRefundDialogKind
        let orderNumber: String
        let fullRefundAmount: String
        let maxRefundAmount: String
        let initialMode: OrderRefundMode
        let remarkPlaceholder: String
        let moneyMaxLength: Int

        static func photographerOrder(orderNumber: String, fullRefundAmount: String) -> Configuration {
            Configuration(
                kind: .photographerOrder,
                orderNumber: orderNumber,
                fullRefundAmount: fullRefundAmount,
                maxRefundAmount: fullRefundAmount,
                initialMode: .full,
                remarkPlaceholder: "请输入退款原因(必填)",
                moneyMaxLength: 10
            )
        }

        static func storeOrder(
            orderNumber: String,
            actualPayAmount: String,
            initialMode: OrderRefundMode
        ) -> Configuration {
            Configuration(
                kind: .storeOrder,
                orderNumber: orderNumber,
                fullRefundAmount: "0",
                maxRefundAmount: actualPayAmount,
                initialMode: initialMode,
                remarkPlaceholder: "请输入退款原因(必填，5-255字)",
                moneyMaxLength: 15
            )
        }
    }

    var onConfirm: ((OrderRefundDialogPayload) -> Void)?
    var onMessage: ((String) -> Void)?

    private let configuration: Configuration
    private var selectedMode: OrderRefundMode

    private let dimView = UIView()
    private let cardView = UIView()
    private let titleLabel = UILabel()
    private let separatorView = UIView()
    private let orderTitleLabel = UILabel()
    private let orderNumberLabel = UILabel()
    private let refundModeTitleLabel = UILabel()
    private let modeButtonStack = UIStackView()
    private let fullRefundButton = UIButton(type: .system)
    private let partialRefundButton = UIButton(type: .system)
    private let amountGroupView = UIView()
    private let amountTitleLabel = UILabel()
    private let amountContainerView = UIView()
    private let amountField = UITextField()
    private let remarkTitleLabel = UILabel()
    private let remarkContainerView = UIView()
    private let remarkTextView = UITextView()
    private let remarkPlaceholderLabel = UILabel()
    private let actionRow = UIStackView()
    private let cancelButton = UIButton(type: .system)
    private let confirmButton = UIButton(type: .system)

    init(configuration: Configuration) {
        self.configuration = configuration
        self.selectedMode = configuration.initialMode
        super.init(frame: .zero)
        setupUI()
        applyMode(animated: false)
    }

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

    func show(in parent: UIView) {
        frame = parent.bounds
        autoresizingMask = [.flexibleWidth, .flexibleHeight]
        alpha = 0
        parent.addSubview(self)
        UIView.animate(withDuration: 0.2) {
            self.alpha = 1
        }
    }

    func dismiss() {
        endEditing(true)
        UIView.animate(withDuration: 0.2, animations: {
            self.alpha = 0
        }, completion: { _ in
            self.removeFromSuperview()
        })
    }

    private func setupUI() {
        keyboardAvoidingContentView = cardView
        keyboardAvoidingMinimumSpacing = AppSpacing.sm

        dimView.backgroundColor = UIColor.black.withAlphaComponent(0.2)
        dimView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(cancelTapped)))

        cardView.backgroundColor = .white
        cardView.layer.cornerRadius = AppRadius.md
        cardView.clipsToBounds = true

        titleLabel.text = "订单退款"
        titleLabel.font = .systemFont(ofSize: 18, weight: .bold)
        titleLabel.textColor = .black

        separatorView.backgroundColor = UIColor(hex: 0xF4F4F4)

        configureSectionLabel(orderTitleLabel, text: "订单号")
        orderNumberLabel.text = configuration.orderNumber
        orderNumberLabel.font = .systemFont(ofSize: 16)
        orderNumberLabel.textColor = .black
        orderNumberLabel.numberOfLines = 0

        configureSectionLabel(refundModeTitleLabel, text: "退款方式")
        configureModeButton(fullRefundButton, title: "全额退款")
        configureModeButton(partialRefundButton, title: "部分退款")
        fullRefundButton.addTarget(self, action: #selector(fullRefundTapped), for: .touchUpInside)
        partialRefundButton.addTarget(self, action: #selector(partialRefundTapped), for: .touchUpInside)

        modeButtonStack.axis = .horizontal
        modeButtonStack.spacing = AppSpacing.md
        modeButtonStack.distribution = .fillEqually

        configureSectionLabel(amountTitleLabel, text: "退款金额")
        amountContainerView.layer.borderWidth = 1
        amountContainerView.layer.borderColor = UIColor(hex: 0xB6BECA).cgColor
        amountContainerView.layer.cornerRadius = AppRadius.sm

        amountField.placeholder = "请输入退款金额"
        amountField.font = .systemFont(ofSize: 14)
        amountField.textColor = AppColor.textPrimary
        amountField.keyboardType = .decimalPad
        amountField.borderStyle = .none
        amountField.addTarget(self, action: #selector(amountChanged), for: .editingChanged)

        configureSectionLabel(remarkTitleLabel, text: "退款备注")
        remarkContainerView.layer.borderWidth = 1
        remarkContainerView.layer.borderColor = UIColor(hex: 0xB6BECA).cgColor
        remarkContainerView.layer.cornerRadius = AppRadius.sm

        remarkTextView.font = .systemFont(ofSize: 14)
        remarkTextView.textColor = AppColor.textPrimary
        remarkTextView.backgroundColor = .clear
        remarkTextView.textContainerInset = UIEdgeInsets(top: 10, left: 8, bottom: 10, right: 8)
        remarkTextView.delegate = self

        remarkPlaceholderLabel.text = configuration.remarkPlaceholder
        remarkPlaceholderLabel.font = .systemFont(ofSize: 14)
        remarkPlaceholderLabel.textColor = AppColor.textTertiary

        actionRow.axis = .horizontal
        actionRow.alignment = .center
        actionRow.spacing = AppSpacing.xs

        configureActionButton(cancelButton, title: "取消", foreground: AppColor.primary, background: AppColor.primaryLight)
        configureActionButton(confirmButton, title: "确认", foreground: .white, background: AppColor.primary)
        cancelButton.addTarget(self, action: #selector(cancelTapped), for: .touchUpInside)
        confirmButton.addTarget(self, action: #selector(confirmTapped), for: .touchUpInside)

        addSubview(dimView)
        addSubview(cardView)
        cardView.addSubview(titleLabel)
        cardView.addSubview(separatorView)
        cardView.addSubview(orderTitleLabel)
        cardView.addSubview(orderNumberLabel)
        cardView.addSubview(refundModeTitleLabel)
        cardView.addSubview(modeButtonStack)
        modeButtonStack.addArrangedSubview(fullRefundButton)
        modeButtonStack.addArrangedSubview(partialRefundButton)
        cardView.addSubview(amountGroupView)
        amountGroupView.addSubview(amountTitleLabel)
        amountGroupView.addSubview(amountContainerView)
        amountContainerView.addSubview(amountField)
        cardView.addSubview(remarkTitleLabel)
        cardView.addSubview(remarkContainerView)
        remarkContainerView.addSubview(remarkTextView)
        remarkContainerView.addSubview(remarkPlaceholderLabel)
        cardView.addSubview(actionRow)
        actionRow.addArrangedSubview(cancelButton)
        actionRow.addArrangedSubview(confirmButton)

        dimView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        cardView.snp.makeConstraints { make in
            make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
            keyboardAvoidingCenterYConstraint = make.centerY.equalToSuperview().constraint
        }
        titleLabel.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(AppSpacing.sm)
            make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
        }
        separatorView.snp.makeConstraints { make in
            make.top.equalTo(titleLabel.snp.bottom).offset(AppSpacing.sm)
            make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
            make.height.equalTo(1)
        }
        orderTitleLabel.snp.makeConstraints { make in
            make.top.equalTo(separatorView.snp.bottom).offset(AppSpacing.md)
            make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
        }
        orderNumberLabel.snp.makeConstraints { make in
            make.top.equalTo(orderTitleLabel.snp.bottom).offset(AppSpacing.xs)
            make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
        }
        refundModeTitleLabel.snp.makeConstraints { make in
            make.top.equalTo(orderNumberLabel.snp.bottom).offset(Layout.sectionGap)
            make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
        }
        modeButtonStack.snp.makeConstraints { make in
            make.top.equalTo(refundModeTitleLabel.snp.bottom).offset(AppSpacing.xs)
            make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
            make.height.equalTo(Layout.controlHeight)
        }
        amountGroupView.snp.makeConstraints { make in
            make.top.equalTo(modeButtonStack.snp.bottom).offset(Layout.formGap)
            make.leading.trailing.equalToSuperview()
            make.height.equalTo(Layout.amountGroupHeight)
        }
        amountTitleLabel.snp.makeConstraints { make in
            make.top.leading.trailing.equalToSuperview().inset(UIEdgeInsets(top: 0, left: AppSpacing.md, bottom: 0, right: AppSpacing.md))
        }
        amountContainerView.snp.makeConstraints { make in
            make.top.equalTo(amountTitleLabel.snp.bottom).offset(AppSpacing.xs)
            make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
            make.height.equalTo(Layout.controlHeight)
        }
        amountField.snp.makeConstraints { make in
            make.leading.trailing.equalToSuperview().inset(AppSpacing.sm)
            make.centerY.equalToSuperview()
        }
        remarkTitleLabel.snp.makeConstraints { make in
            make.top.equalTo(amountGroupView.snp.bottom).offset(Layout.formGap)
            make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
        }
        remarkContainerView.snp.makeConstraints { make in
            make.top.equalTo(remarkTitleLabel.snp.bottom).offset(AppSpacing.xs)
            make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
            make.height.equalTo(Layout.remarkHeight)
        }
        remarkTextView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        remarkPlaceholderLabel.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(16)
            make.leading.trailing.equalToSuperview().inset(AppSpacing.sm)
        }
        actionRow.snp.makeConstraints { make in
            make.top.equalTo(remarkContainerView.snp.bottom).offset(Layout.actionTop)
            make.trailing.equalToSuperview().inset(AppSpacing.md)
            make.bottom.equalToSuperview().inset(Layout.bottomInset)
        }
        [cancelButton, confirmButton].forEach { button in
            button.snp.makeConstraints { make in
                make.width.equalTo(84)
                make.height.equalTo(38)
            }
        }
    }

    private func configureSectionLabel(_ label: UILabel, text: String) {
        label.text = text
        label.font = .systemFont(ofSize: 16)
        label.textColor = UIColor(hex: 0x4B5563)
    }

    private func configureModeButton(_ button: UIButton, title: String) {
        button.setTitle(title, for: .normal)
        button.titleLabel?.font = .systemFont(ofSize: 14)
        button.layer.cornerRadius = AppRadius.sm
        button.layer.borderWidth = 1
    }

    private func configureActionButton(_ button: UIButton, title: String, foreground: UIColor, background: UIColor) {
        button.setTitle(title, for: .normal)
        button.setTitleColor(foreground, for: .normal)
        button.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
        button.backgroundColor = background
        button.layer.cornerRadius = AppRadius.sm
    }

    private func applyMode(animated: Bool) {
        let amountHidden = selectedMode == .full
        amountGroupView.isHidden = amountHidden
        amountGroupView.snp.updateConstraints { make in
            make.height.equalTo(amountHidden ? 0 : Layout.amountGroupHeight)
        }
        remarkTitleLabel.snp.remakeConstraints { make in
            make.top.equalTo((amountHidden ? modeButtonStack : amountGroupView).snp.bottom).offset(Layout.formGap)
            make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
        }

        updateModeButton(fullRefundButton, selected: selectedMode == .full)
        updateModeButton(partialRefundButton, selected: selectedMode == .partial)
        let changes = { self.layoutIfNeeded() }
        if animated {
            UIView.animate(withDuration: 0.2, animations: changes)
        } else {
            changes()
        }
    }

    private func updateModeButton(_ button: UIButton, selected: Bool) {
        button.backgroundColor = selected ? AppColor.primary : .white
        button.layer.borderColor = selected ? UIColor.clear.cgColor : UIColor(hex: 0xB6BECA).cgColor
        button.setTitleColor(selected ? .white : UIColor(hex: 0x4B5563), for: .normal)
    }

    func textViewDidChange(_ textView: UITextView) {
        if textView.text.count > 255 {
            textView.text = String(textView.text.prefix(255))
        }
        remarkPlaceholderLabel.isHidden = !textView.text.isEmpty
    }

    @objc private func amountChanged() {
        let filtered = OrderRefundDialogValidation.filterMoneyInput(
            amountField.text ?? "",
            maxLength: configuration.moneyMaxLength
        )
        if amountField.text != filtered {
            amountField.text = filtered
        }
    }

    @objc private func fullRefundTapped() {
        selectedMode = .full
        amountField.text = configuration.kind == .storeOrder ? configuration.maxRefundAmount : configuration.fullRefundAmount
        applyMode(animated: true)
    }

    @objc private func partialRefundTapped() {
        selectedMode = .partial
        amountField.text = ""
        applyMode(animated: true)
        amountField.becomeFirstResponder()
    }

    @objc private func cancelTapped() {
        dismiss()
    }

    @objc private func confirmTapped() {
        let result = OrderRefundDialogValidation.validate(
            kind: configuration.kind,
            mode: selectedMode,
            amountText: amountField.text ?? "",
            reason: remarkTextView.text ?? "",
            fullRefundAmount: configuration.fullRefundAmount,
            maxRefundAmount: configuration.maxRefundAmount
        )
        switch result {
        case .success(let payload):
            onConfirm?(payload)
            dismiss()
        case .failure(let error):
            onMessage?(error.message)
        }
    }
}

enum OrderSignInAlertController {
    static func present(from presenter: UIViewController, response: OrderSignInResponse) {
        let message = """
        项目：\(response.projectName)
        景区：\(response.scenicName)
        金额：¥\(response.orderAmount)
        手机号：\(response.userPhone)
        """
        let alert = UIAlertController(title: response.checkIn ? "签到成功" : "核销结果", message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "确定", style: .default))
        presenter.present(alert, animated: true)
    }
}

enum WriteOffResultAlertController {
    static func present(from presenter: UIViewController, response: WriteOffOrderResponse) {
        let message = """
        项目：\(response.projectName)
        景区：\(response.scenicName)
        金额：¥\(response.orderAmount)
        手机号：\(response.userPhone)
        """
        let alert = UIAlertController(title: response.orderVerify ? "核销成功" : "核销结果", message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "确定", style: .default))
        presenter.present(alert, animated: true)
    }
}

enum SendGiftAlertController {
    static func present(
        from presenter: UIViewController,
        photoNum: Int,
        videoNum: Int,
        onConfirm: @escaping (Int, Int) -> Void
    ) {
        let alert = UIAlertController(title: "赠送修图", message: nil, preferredStyle: .alert)
        alert.addTextField { $0.placeholder = "赠送照片数"; $0.keyboardType = .numberPad; $0.text = "\(photoNum)" }
        alert.addTextField { $0.placeholder = "赠送视频数"; $0.keyboardType = .numberPad; $0.text = "\(videoNum)" }
        alert.addAction(UIAlertAction(title: "取消", style: .cancel))
        alert.addAction(UIAlertAction(title: "确认", style: .default) { _ in
            let photo = Int(alert.textFields?.first?.text ?? "0") ?? 0
            let video = Int(alert.textFields?.last?.text ?? "0") ?? 0
            onConfirm(photo, video)
        })
        presenter.present(alert, animated: true)
    }
}
