//
//  ScenicQueueViews.swift
//  suixinkan
//

import SnapKit
import UIKit

/// 排队统计 Banner。
final class ScenicQueueStatsBannerView: UIView {
    private let peopleValueLabel = UILabel()
    private let avgValueLabel = UILabel()

    init() {
        super.init(frame: .zero)
        setupUI()
    }

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

    /// 更新统计。
    func configure(summary: ScenicQueueSummary) {
        peopleValueLabel.text = "\(summary.peopleInQueue)"
        avgValueLabel.text = "\(summary.avgWaitMinutes)"
    }

    private func setupUI() {
        backgroundColor = ScenicQueueTokens.bannerBlue

        let left = metricColumn(title: "在排人数", valueLabel: peopleValueLabel, unit: "人")
        let right = metricColumn(title: "平均等待", valueLabel: avgValueLabel, unit: "分钟")
        let divider = UIView()
        divider.backgroundColor = ScenicQueueTokens.bannerDivider

        addSubview(left)
        addSubview(divider)
        addSubview(right)

        left.snp.makeConstraints { make in
            make.leading.top.bottom.equalToSuperview()
            make.trailing.equalTo(divider.snp.leading)
            make.width.equalTo(right)
        }
        divider.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            make.centerY.equalToSuperview()
            make.width.equalTo(0.8)
            make.height.equalTo(42)
        }
        right.snp.makeConstraints { make in
            make.leading.equalTo(divider.snp.trailing)
            make.trailing.top.bottom.equalToSuperview()
        }
    }

    private func metricColumn(title: String, valueLabel: UILabel, unit: String) -> UIView {
        let container = UIView()
        let titleLabel = UILabel()
        titleLabel.text = title
        titleLabel.textColor = ScenicQueueTokens.bannerMutedLabel
        titleLabel.font = ScenicQueueTokens.bannerLabelFont
        titleLabel.textAlignment = .center

        valueLabel.textColor = .white
        valueLabel.font = ScenicQueueTokens.bannerValueFont
        valueLabel.textAlignment = .center

        let unitLabel = UILabel()
        unitLabel.text = unit
        unitLabel.textColor = .white
        unitLabel.font = ScenicQueueTokens.bannerUnitFont

        let valueStack = UIStackView(arrangedSubviews: [valueLabel, unitLabel])
        valueStack.axis = .horizontal
        valueStack.alignment = .lastBaseline
        valueStack.spacing = 2

        let stack = UIStackView(arrangedSubviews: [titleLabel, valueStack])
        stack.axis = .vertical
        stack.alignment = .center
        stack.spacing = 6
        container.addSubview(stack)
        stack.snp.makeConstraints { make in
            make.center.equalToSuperview()
        }
        return container
    }
}

/// 排队列表标签。
final class ScenicQueueTagLabel: UILabel {
    init() {
        super.init(frame: .zero)
        font = ScenicQueueTokens.statusChipFont
        textAlignment = .center
        layer.cornerRadius = ScenicQueueTokens.radiusChip
        clipsToBounds = true
    }

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

    /// 设置标签文案与颜色。
    func configure(text: String, foreground: UIColor, background: UIColor) {
        self.text = text
        textColor = foreground
        backgroundColor = background
    }
}

/// 排队操作按钮。
final class ScenicQueueActionButton: UIButton {
    init(title: String, background: UIColor, foreground: UIColor) {
        super.init(frame: .zero)
        setTitle(title, for: .normal)
        titleLabel?.font = ScenicQueueTokens.buttonPrimaryFont
        setTitleColor(foreground, for: .normal)
        backgroundColor = background
        layer.cornerRadius = ScenicQueueTokens.radiusPrimaryRowButton
        clipsToBounds = true
    }

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

/// 当前排队 cell 交互代理。
protocol ScenicQueueTicketCellDelegate: AnyObject {
    func scenicQueueTicketCellDidTapDial(_ cell: ScenicQueueTicketCell, ticket: ScenicQueueTicket)
    func scenicQueueTicketCellDidTapSkip(_ cell: ScenicQueueTicketCell, ticket: ScenicQueueTicket)
    func scenicQueueTicketCellDidTapPrimary(_ cell: ScenicQueueTicketCell, ticket: ScenicQueueTicket)
    func scenicQueueTicketCellDidTapRecall(_ cell: ScenicQueueTicketCell, ticket: ScenicQueueTicket)
    func scenicQueueTicketCellDidTapComplete(_ cell: ScenicQueueTicketCell, ticket: ScenicQueueTicket)
    func scenicQueueTicketCellDidTapMark(_ cell: ScenicQueueTicketCell, ticket: ScenicQueueTicket)
}

/// 当前排队列表 cell。
final class ScenicQueueTicketCell: UITableViewCell {
    static let reuseIdentifier = "ScenicQueueTicketCell"

    weak var delegate: ScenicQueueTicketCellDelegate?

    private let cardView = UIView()
    private let queueNoLabel = UILabel()
    private let markButton = UIButton(type: .system)
    private let tagStack = UIStackView()
    private let metaStack = UIStackView()
    private let actionsStack = UIStackView()
    private let recallButton = ScenicQueueActionButton(title: "重新叫号", background: ScenicQueueTokens.buttonCompleteBackground, foreground: ScenicQueueTokens.bannerBlue)
    private let completeButton = ScenicQueueActionButton(title: "完成", background: ScenicQueueTokens.buttonCompleteBackground, foreground: ScenicQueueTokens.bannerBlue)
    private var ticket: ScenicQueueTicket?
    private var showStartShootingButton = true

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupUI()
    }

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

    /// 配置当前排队 cell。
    func configure(ticket: ScenicQueueTicket, shootingQueueNo: String?, remainSeconds: Int, showStartShootingButton: Bool) {
        self.ticket = ticket
        self.showStartShootingButton = showStartShootingButton
        queueNoLabel.text = ticket.queueNo
        markButton.isHidden = ticket.markAsPhotog == 1
        rebuildTags(ticket)
        rebuildMeta(ticket)
        rebuildActions(ticket: ticket, shootingQueueNo: shootingQueueNo, remainSeconds: remainSeconds)
    }

    private func setupUI() {
        selectionStyle = .none
        backgroundColor = .clear
        contentView.backgroundColor = .clear

        cardView.backgroundColor = .white
        cardView.layer.cornerRadius = ScenicQueueTokens.radiusCard
        cardView.layer.borderWidth = 1
        cardView.layer.borderColor = ScenicQueueTokens.cardOutline.cgColor
        cardView.clipsToBounds = true
        contentView.addSubview(cardView)

        queueNoLabel.font = ScenicQueueTokens.ticketIdFont
        queueNoLabel.textColor = AppColor.textPrimary

        markButton.setTitle("标记", for: .normal)
        markButton.titleLabel?.font = ScenicQueueTokens.rowLabelFont
        markButton.setTitleColor(ScenicQueueTokens.bannerBlue, for: .normal)
        markButton.addTarget(self, action: #selector(markTapped), for: .touchUpInside)

        let titleRow = UIStackView(arrangedSubviews: [queueNoLabel, markButton, UIView(), tagStack])
        titleRow.axis = .horizontal
        titleRow.alignment = .center
        titleRow.spacing = 4
        tagStack.axis = .horizontal
        tagStack.spacing = 6
        tagStack.alignment = .center

        metaStack.axis = .vertical
        metaStack.spacing = 10

        actionsStack.axis = .vertical
        actionsStack.spacing = 10

        let stack = UIStackView(arrangedSubviews: [titleRow, metaStack, actionsStack])
        stack.axis = .vertical
        stack.spacing = 12
        cardView.addSubview(stack)

        cardView.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(UIEdgeInsets(top: 5, left: 12, bottom: 5, right: 12))
        }
        stack.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(UIEdgeInsets(top: 14, left: 16, bottom: 14, right: 16))
        }
    }

    private func rebuildTags(_ ticket: ScenicQueueTicket) {
        tagStack.arrangedSubviews.forEach { $0.removeFromSuperview() }
        if ticket.isMissRequeue {
            tagStack.addArrangedSubview(tag(text: ticket.missRequeueText, fg: ScenicQueueTokens.tagMissRequeueForeground, bg: ScenicQueueTokens.tagMissRequeueBackground))
        }
        let statusColors: (UIColor, UIColor) = ticket.status == .waiting
            ? (ScenicQueueTokens.tagWaitingForeground, ScenicQueueTokens.tagWaitingBackground)
            : (ScenicQueueTokens.tagCalledForeground, ScenicQueueTokens.tagCalledBackground)
        tagStack.addArrangedSubview(tag(text: ticket.statusText, fg: statusColors.0, bg: statusColors.1))
    }

    private func rebuildMeta(_ ticket: ScenicQueueTicket) {
        metaStack.arrangedSubviews.forEach { $0.removeFromSuperview() }
        let identityRow = UIStackView()
        identityRow.axis = .horizontal
        identityRow.spacing = 6
        if ticket.shouldShowIdentityTag {
            let colors = identityColors(ticket.identityTag)
            identityRow.addArrangedSubview(tag(text: ticket.identityTag, fg: colors.fg, bg: colors.bg))
        }
        if !ticket.queueBanLabel.isEmpty {
            identityRow.addArrangedSubview(tag(text: ticket.queueBanLabel, fg: ScenicQueueTokens.tagBanForeground, bg: ScenicQueueTokens.tagBanBackground))
        }
        if !identityRow.arrangedSubviews.isEmpty {
            metaStack.addArrangedSubview(identityRow)
        }
        metaStack.addArrangedSubview(kvRow(label: "取号时间", value: ticket.queueTimeDisplay))
        metaStack.addArrangedSubview(kvRow(label: "手机号", value: ticket.phoneMasked, tap: #selector(dialTapped)))
        metaStack.addArrangedSubview(kvRow(label: "等待", value: "\(ticket.waitMinutes)分钟", accent: true))
        metaStack.addArrangedSubview(kvRow(label: "前方", value: "\(ticket.peopleAhead)人", accent: true))
        metaStack.addArrangedSubview(kvRow(label: "排号次数", value: "\(ticket.queueCountToday)次", accent: true))
    }

    private func rebuildActions(ticket: ScenicQueueTicket, shootingQueueNo: String?, remainSeconds: Int) {
        actionsStack.arrangedSubviews.forEach { $0.removeFromSuperview() }
        let state = ScenicQueueTicketActionState.make(
            ticket: ticket,
            shootingQueueNo: shootingQueueNo,
            remainSeconds: remainSeconds,
            showStartShootingButton: showStartShootingButton
        )
        let skip = ScenicQueueActionButton(title: "过号", background: ScenicQueueTokens.buttonSkipBackground, foreground: ScenicQueueTokens.buttonSkipForeground)
        skip.addTarget(self, action: #selector(skipTapped), for: .touchUpInside)
        skip.isEnabled = state.skipEnabled
        skip.alpha = state.skipEnabled ? 1 : 0.45
        let row = UIStackView(arrangedSubviews: [skip])
        row.axis = .horizontal
        row.spacing = 10
        row.distribution = .fillProportionally
        if state.primaryVisible {
            let primary = ScenicQueueActionButton(title: state.primaryTitle, background: ScenicQueueTokens.bannerBlue, foreground: .white)
            primary.isEnabled = state.primaryEnabled
            primary.alpha = state.primaryEnabled ? 1 : 0.65
            primary.addTarget(self, action: #selector(primaryTapped), for: .touchUpInside)
            row.addArrangedSubview(primary)
            skip.snp.makeConstraints { $0.width.equalTo(primary).multipliedBy(0.56) }
        }
        row.snp.makeConstraints { $0.height.equalTo(46) }
        actionsStack.addArrangedSubview(row)
        recallButton.removeTarget(nil, action: nil, for: .allEvents)
        completeButton.removeTarget(nil, action: nil, for: .allEvents)
        if state.recallVisible {
            recallButton.addTarget(self, action: #selector(recallTapped), for: .touchUpInside)
            recallButton.snp.makeConstraints { make in make.height.equalTo(40) }
            actionsStack.addArrangedSubview(recallButton)
        }
        if state.completeVisible {
            completeButton.addTarget(self, action: #selector(completeTapped), for: .touchUpInside)
            completeButton.snp.makeConstraints { make in make.height.equalTo(40) }
            actionsStack.addArrangedSubview(completeButton)
        }
    }

    private func tag(text: String, fg: UIColor, bg: UIColor) -> UILabel {
        let label = PaddingLabel(insets: UIEdgeInsets(top: 5, left: 8, bottom: 5, right: 8))
        label.font = ScenicQueueTokens.statusChipFont
        label.textColor = fg
        label.backgroundColor = bg
        label.text = text
        label.layer.cornerRadius = ScenicQueueTokens.radiusChip
        label.clipsToBounds = true
        return label
    }

    private func identityColors(_ label: String) -> (fg: UIColor, bg: UIColor) {
        switch label.trimmingCharacters(in: .whitespacesAndNewlines) {
        case "打野":
            return (UIColor(hex: 0xF5222D), UIColor(hex: 0xFFF1F0))
        case "摄影师":
            return (UIColor(hex: 0x1890FF), UIColor(hex: 0xE6F7FF))
        default:
            return (UIColor(hex: 0x4B5563), UIColor(hex: 0xF3F4F6))
        }
    }

    private func kvRow(label: String, value: String, accent: Bool = false, tap: Selector? = nil) -> UIView {
        let row = UIView()
        let left = UILabel()
        left.text = label
        left.font = ScenicQueueTokens.metaLabelFont
        left.textColor = AppColor.textTertiary
        let right = PaddingLabel(insets: accent ? UIEdgeInsets(top: 1, left: 6, bottom: 1, right: 6) : .zero)
        right.text = value
        right.font = accent ? ScenicQueueTokens.metaAccentFont : ScenicQueueTokens.rowLabelFont
        right.textColor = accent ? ScenicQueueTokens.bannerBlue : AppColor.textPrimary
        right.backgroundColor = accent ? AppColor.primaryLight : .clear
        right.layer.cornerRadius = 2
        right.clipsToBounds = true
        row.addSubview(left)
        let valueContainer = UIStackView(arrangedSubviews: [right])
        valueContainer.axis = .horizontal
        valueContainer.alignment = .center
        valueContainer.spacing = 8
        if let tap {
            let dial = UIButton(type: .system)
            dial.backgroundColor = ScenicQueueTokens.bannerBlue
            dial.tintColor = .white
            dial.setImage(UIImage(systemName: "phone.fill")?.withConfiguration(UIImage.SymbolConfiguration(pointSize: 15, weight: .medium)), for: .normal)
            dial.layer.cornerRadius = 16
            dial.addTarget(self, action: tap, for: .touchUpInside)
            valueContainer.addArrangedSubview(dial)
            dial.snp.makeConstraints { $0.size.equalTo(32) }
        }
        row.addSubview(valueContainer)
        left.snp.makeConstraints { make in
            make.leading.centerY.equalToSuperview()
            make.top.bottom.equalToSuperview()
        }
        valueContainer.snp.makeConstraints { make in
            make.trailing.centerY.equalToSuperview()
            make.leading.greaterThanOrEqualTo(left.snp.trailing).offset(12)
        }
        return row
    }

    @objc private func dialTapped() {
        guard let ticket else { return }
        delegate?.scenicQueueTicketCellDidTapDial(self, ticket: ticket)
    }

    @objc private func skipTapped() {
        guard let ticket else { return }
        delegate?.scenicQueueTicketCellDidTapSkip(self, ticket: ticket)
    }

    @objc private func primaryTapped() {
        guard let ticket else { return }
        delegate?.scenicQueueTicketCellDidTapPrimary(self, ticket: ticket)
    }

    @objc private func recallTapped() {
        guard let ticket else { return }
        delegate?.scenicQueueTicketCellDidTapRecall(self, ticket: ticket)
    }

    @objc private func completeTapped() {
        guard let ticket else { return }
        delegate?.scenicQueueTicketCellDidTapComplete(self, ticket: ticket)
    }

    @objc private func markTapped() {
        guard let ticket else { return }
        delegate?.scenicQueueTicketCellDidTapMark(self, ticket: ticket)
    }
}

/// 过号列表 cell 代理。
protocol ScenicQueueSkippedCellDelegate: AnyObject {
    func scenicQueueSkippedCellDidTapDial(_ cell: ScenicQueueSkippedCell, ticket: ScenicQueueSkippedTicket)
    func scenicQueueSkippedCellDidTapRequeue(_ cell: ScenicQueueSkippedCell, ticket: ScenicQueueSkippedTicket)
}

/// 过号列表 cell。
final class ScenicQueueSkippedCell: UITableViewCell {
    static let reuseIdentifier = "ScenicQueueSkippedCell"

    weak var delegate: ScenicQueueSkippedCellDelegate?
    private let cardView = UIView()
    private let queueNoLabel = UILabel()
    private let tagStack = UIStackView()
    private let metaStack = UIStackView()
    private let requeueButton = ScenicQueueActionButton(title: "重新排队", background: ScenicQueueTokens.bannerBlue, foreground: .white)
    private var ticket: ScenicQueueSkippedTicket?

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupUI()
    }

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

    /// 配置过号 cell。
    func configure(ticket: ScenicQueueSkippedTicket) {
        self.ticket = ticket
        queueNoLabel.text = ticket.queueNo
        rebuildTags(ticket)
        rebuildMeta(ticket)
    }

    private func setupUI() {
        selectionStyle = .none
        backgroundColor = .clear
        cardView.backgroundColor = .white
        cardView.layer.cornerRadius = ScenicQueueTokens.radiusCard
        cardView.layer.borderWidth = 1
        cardView.layer.borderColor = ScenicQueueTokens.cardOutline.cgColor
        contentView.addSubview(cardView)

        queueNoLabel.font = ScenicQueueTokens.ticketIdFont
        queueNoLabel.textColor = AppColor.textPrimary
        tagStack.axis = .horizontal
        tagStack.spacing = 6
        let titleRow = UIStackView(arrangedSubviews: [queueNoLabel, UIView(), tagStack])
        titleRow.axis = .horizontal
        titleRow.alignment = .center

        metaStack.axis = .vertical
        metaStack.spacing = 10
        requeueButton.addTarget(self, action: #selector(requeueTapped), for: .touchUpInside)

        let stack = UIStackView(arrangedSubviews: [titleRow, metaStack, requeueButton])
        stack.axis = .vertical
        stack.spacing = 12
        cardView.addSubview(stack)

        cardView.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(UIEdgeInsets(top: 5, left: 12, bottom: 5, right: 12))
        }
        stack.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(UIEdgeInsets(top: 14, left: 16, bottom: 14, right: 16))
        }
        requeueButton.snp.makeConstraints { make in
            make.height.equalTo(46)
        }
    }

    private func rebuildTags(_ ticket: ScenicQueueSkippedTicket) {
        tagStack.arrangedSubviews.forEach { $0.removeFromSuperview() }
        if !ticket.queueBanLabel.isEmpty {
            tagStack.addArrangedSubview(tag(text: ticket.queueBanLabel, fg: ScenicQueueTokens.tagBanForeground, bg: ScenicQueueTokens.tagBanBackground))
        }
        if ticket.isMissRequeue {
            tagStack.addArrangedSubview(tag(text: ticket.missRequeueText, fg: ScenicQueueTokens.tagMissRequeueForeground, bg: ScenicQueueTokens.tagMissRequeueBackground))
        }
        tagStack.addArrangedSubview(tag(text: ticket.statusText, fg: ScenicQueueTokens.tagSkippedForeground, bg: ScenicQueueTokens.tagSkippedBackground))
    }

    private func rebuildMeta(_ ticket: ScenicQueueSkippedTicket) {
        metaStack.arrangedSubviews.forEach { $0.removeFromSuperview() }
        metaStack.addArrangedSubview(kvRow(label: "手机号", value: ticket.phoneMasked, tap: #selector(dialTapped)))
        if !ticket.skippedTimeDisplay.isEmpty {
            metaStack.addArrangedSubview(kvRow(label: "过号时间", value: ticket.skippedTimeDisplay))
        }
    }

    private func tag(text: String, fg: UIColor, bg: UIColor) -> UILabel {
        let label = PaddingLabel(insets: UIEdgeInsets(top: 5, left: 8, bottom: 5, right: 8))
        label.text = text
        label.font = ScenicQueueTokens.statusChipFont
        label.textColor = fg
        label.backgroundColor = bg
        label.layer.cornerRadius = ScenicQueueTokens.radiusChip
        label.clipsToBounds = true
        return label
    }

    private func kvRow(label: String, value: String, tap: Selector? = nil) -> UIView {
        let row = UIView()
        let left = UILabel()
        left.text = label
        left.font = ScenicQueueTokens.metaLabelFont
        left.textColor = AppColor.textTertiary
        let right = UILabel()
        right.text = value
        right.font = ScenicQueueTokens.phoneMaskedFont
        right.textColor = AppColor.textPrimary
        row.addSubview(left)
        let valueContainer = UIStackView(arrangedSubviews: [right])
        valueContainer.axis = .horizontal
        valueContainer.alignment = .center
        valueContainer.spacing = 8
        if let tap {
            let dial = UIButton(type: .system)
            dial.backgroundColor = ScenicQueueTokens.bannerBlue
            dial.tintColor = .white
            dial.setImage(UIImage(systemName: "phone.fill")?.withConfiguration(UIImage.SymbolConfiguration(pointSize: 15, weight: .medium)), for: .normal)
            dial.layer.cornerRadius = 16
            dial.addTarget(self, action: tap, for: .touchUpInside)
            valueContainer.addArrangedSubview(dial)
            dial.snp.makeConstraints { $0.size.equalTo(32) }
        }
        row.addSubview(valueContainer)
        left.snp.makeConstraints { make in
            make.leading.centerY.equalToSuperview()
            make.top.bottom.equalToSuperview()
        }
        valueContainer.snp.makeConstraints { make in
            make.trailing.centerY.equalToSuperview()
            make.leading.greaterThanOrEqualTo(left.snp.trailing).offset(12)
        }
        return row
    }

    @objc private func dialTapped() {
        guard let ticket else { return }
        delegate?.scenicQueueSkippedCellDidTapDial(self, ticket: ticket)
    }

    @objc private func requeueTapped() {
        guard let ticket else { return }
        delegate?.scenicQueueSkippedCellDidTapRequeue(self, ticket: ticket)
    }
}

/// 带内边距的 UILabel。
final class PaddingLabel: UILabel {
    private let insets: UIEdgeInsets

    init(insets: UIEdgeInsets) {
        self.insets = insets
        super.init(frame: .zero)
    }

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

    override func drawText(in rect: CGRect) {
        super.drawText(in: rect.inset(by: insets))
    }

    override var intrinsicContentSize: CGSize {
        let size = super.intrinsicContentSize
        return CGSize(width: size.width + insets.left + insets.right, height: size.height + insets.top + insets.bottom)
    }
}
