//
//  MaterialDetailViewController.swift
//  suixinkan
//

import AVFoundation
import Kingfisher
import SnapKit
import UIKit

/// 素材详情页，对齐 Android `MaterialDetailNewScreen`。
/// 素材详情页，展示轮播、信息、统计、审核与底部操作。
final class MaterialDetailViewController: BaseViewController {
    private let viewModel: MaterialDetailViewModel
    private let api: any MaterialManagementServing

    private let scrollView = UIScrollView()
    private let contentStack = UIStackView()
    private let carouselView = MaterialMediaCarouselView()
    private let infoSection = MaterialDetailInfoSection()
    private let uploaderSection = MaterialDetailUploaderSection()
    private let reviewSection = MaterialDetailReviewSection()
    private let bottomBar = UIView()
    private let deleteButton = UIButton(type: .system)
    private let editButton = UIButton(type: .system)

    var onDeleted: ((Int) -> Void)?
    var onEdited: (() -> Void)?

    /// 初始化素材详情页。
    init(
        materialId: Int,
        api: (any MaterialManagementServing)? = nil
    ) {
        viewModel = MaterialDetailViewModel(materialId: materialId)
        self.api = api ?? NetworkServices.shared.materialManagementAPI
        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: 0xF4F4F4)
        contentStack.axis = .vertical
        contentStack.spacing = 0
        scrollView.backgroundColor = UIColor(hex: 0xF4F4F4)
        bottomBar.backgroundColor = .white

        configureBottomButton(deleteButton, title: "删除", backgroundColor: UIColor(hex: 0xEFF6FF), titleColor: AppColor.primary)
        configureBottomButton(editButton, title: "编辑", backgroundColor: AppColor.primary, titleColor: .white)

        view.addSubview(scrollView)
        scrollView.addSubview(contentStack)
        contentStack.addArrangedSubview(carouselView)
        contentStack.addArrangedSubview(infoSection)
        contentStack.addArrangedSubview(makeVerticalSpacer(height: 12))
        contentStack.addArrangedSubview(uploaderSection)
        contentStack.addArrangedSubview(makeVerticalSpacer(height: 12))
        contentStack.addArrangedSubview(reviewSection)
        contentStack.addArrangedSubview(makeVerticalSpacer(height: 16))
        view.addSubview(bottomBar)
        bottomBar.addSubview(deleteButton)
        bottomBar.addSubview(editButton)
    }

    override func setupConstraints() {
        bottomBar.snp.makeConstraints { make in
            make.leading.trailing.bottom.equalToSuperview()
        }
        deleteButton.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(16)
            make.leading.equalToSuperview().offset(16)
            make.width.equalTo(100)
            make.height.equalTo(48)
            make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-16)
        }
        editButton.snp.makeConstraints { make in
            make.top.height.equalTo(deleteButton)
            make.leading.equalTo(deleteButton.snp.trailing).offset(12)
            make.trailing.equalToSuperview().inset(16)
        }
        scrollView.snp.makeConstraints { make in
            make.top.leading.trailing.equalTo(view.safeAreaLayoutGuide)
            make.bottom.equalTo(bottomBar.snp.top)
        }
        contentStack.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.width.equalTo(scrollView)
        }
        carouselView.snp.makeConstraints { make in
            make.height.equalTo(carouselView.snp.width).multipliedBy(9.0 / 16.0)
        }
    }

    override func bindActions() {
        viewModel.onStateChange = { [weak self] in
            Task { @MainActor in self?.applyViewModel() }
        }
        viewModel.onShowMessage = { [weak self] message in
            Task { @MainActor in self?.showToast(message) }
        }
        viewModel.onDeleted = { [weak self] id in
            Task { @MainActor in
                self?.onDeleted?(id)
                self?.navigationController?.popViewController(animated: true)
            }
        }
        deleteButton.addTarget(self, action: #selector(deleteTapped), for: .touchUpInside)
        editButton.addTarget(self, action: #selector(editTapped), for: .touchUpInside)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        Task { await viewModel.load(api: api) }
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        carouselView.pause()
    }

    private func configureBottomButton(_ button: UIButton, title: String, backgroundColor: UIColor, titleColor: UIColor) {
        button.setTitle(title, for: .normal)
        button.setTitleColor(titleColor, for: .normal)
        button.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
        button.backgroundColor = backgroundColor
        button.layer.cornerRadius = 8
    }

    private func makeVerticalSpacer(height: CGFloat) -> UIView {
        let spacer = UIView()
        spacer.backgroundColor = .clear
        spacer.snp.makeConstraints { make in
            make.height.equalTo(height)
        }
        return spacer
    }

    @MainActor
    private func applyViewModel() {
        if (viewModel.isLoading || viewModel.isDeleting) && viewModel.detail == nil {
            showLoading()
        } else {
            hideLoading()
        }
        guard let detail = viewModel.detail else { return }
        carouselView.apply(media: detail.mediaList ?? [])
        infoSection.apply(detail: detail)
        uploaderSection.apply(detail: detail)
        reviewSection.apply(detail: detail)
    }

    @objc private func deleteTapped() {
        let dialog = MaterialDeleteDialogViewController(itemName: viewModel.detail?.name ?? "") { [weak self] in
            guard let self else { return }
            Task {
                self.showLoading()
                await self.viewModel.delete(api: self.api)
                self.hideLoading()
            }
        }
        present(dialog, animated: true)
    }

    @objc private func editTapped() {
        let controller = MaterialFormViewController(mode: .edit(id: viewModel.materialId))
        controller.onSubmitSuccess = { [weak self] in
            guard let self else { return }
            self.onEdited?()
            Task { await self.viewModel.load(api: self.api) }
        }
        navigationController?.pushViewController(controller, animated: true)
    }
}

/// 素材详情无限轮播的页码映射规则。
struct MaterialCarouselIndexMapper {
    /// 初始渲染页；多媒体时跳过头部复制页。
    static func initialRenderedPage(mediaCount: Int) -> Int {
        mediaCount > 1 ? 1 : 0
    }

    /// 将头尾复制页归一到对应的真实渲染页。
    static func normalizedRenderedPage(_ page: Int, mediaCount: Int) -> Int {
        guard mediaCount > 1 else { return 0 }
        if page <= 0 { return mediaCount }
        if page >= mediaCount + 1 { return 1 }
        return page
    }

    /// 将渲染页映射到圆点使用的真实素材索引。
    static func logicalPage(renderedPage: Int, mediaCount: Int) -> Int {
        guard mediaCount > 1 else { return 0 }
        return normalizedRenderedPage(renderedPage, mediaCount: mediaCount) - 1
    }
}

/// 素材详情媒体轮播，支持图片自动切换与视频播完切换。
/// 素材详情顶部媒体轮播视图，支持图片与视频播放。
private final class MaterialMediaCarouselView: UIView, UIScrollViewDelegate {
    private let scrollView = UIScrollView()
    private let pageControl = UIPageControl()
    private let placeholderLabel = UILabel()
    private var media: [MaterialDetailMediaItem] = []
    private var renderedMedia: [MaterialDetailMediaItem] = []
    private var players: [Int: AVPlayer] = [:]
    private var playerViews: [Int: MaterialPlayerLayerView] = [:]
    private var timer: Timer?
    private var renderedPage = 0

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor(hex: 0xF5F5F5)
        scrollView.isPagingEnabled = true
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.delegate = self
        scrollView.bounces = false
        pageControl.currentPageIndicatorTintColor = .white
        pageControl.pageIndicatorTintColor = UIColor.white.withAlphaComponent(0.5)
        placeholderLabel.text = "暂无媒体"
        placeholderLabel.font = .systemFont(ofSize: 14)
        placeholderLabel.textColor = AppColor.textSecondary
        placeholderLabel.textAlignment = .center
        addSubview(scrollView)
        addSubview(pageControl)
        addSubview(placeholderLabel)
        scrollView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        pageControl.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            make.bottom.equalToSuperview().inset(8)
        }
        placeholderLabel.snp.makeConstraints { make in
            make.center.equalToSuperview()
        }
    }

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

    override func layoutSubviews() {
        super.layoutSubviews()
        layoutPages()
    }

    /// 应用媒体列表。
    func apply(media: [MaterialDetailMediaItem]) {
        stopTimer()
        NotificationCenter.default.removeObserver(self)
        players.values.forEach { $0.pause() }
        players.removeAll()
        playerViews.removeAll()
        self.media = media
        renderedMedia = media.count > 1 ? [media.last!] + media + [media.first!] : media
        scrollView.subviews.forEach { $0.removeFromSuperview() }
        pageControl.numberOfPages = media.count
        pageControl.currentPage = 0
        pageControl.isHidden = media.count <= 1
        placeholderLabel.isHidden = !media.isEmpty
        scrollView.isHidden = media.isEmpty
        guard !media.isEmpty else { return }

        renderedPage = MaterialCarouselIndexMapper.initialRenderedPage(mediaCount: media.count)
        for (index, item) in renderedMedia.enumerated() {
            let page = UIView()
            page.backgroundColor = UIColor(hex: 0xF5F5F5)
            scrollView.addSubview(page)
            if item.type == 2 {
                addVideo(urlText: item.displayURL, to: page, index: index)
            } else {
                addImage(urlText: item.displayURL, to: page)
            }
        }
        setNeedsLayout()
        layoutIfNeeded()
        scrollView.contentOffset = CGPoint(x: CGFloat(renderedPage) * bounds.width, y: 0)
        playCurrentPageIfNeeded()
    }

    /// 暂停当前轮播。
    func pause() {
        stopTimer()
        players.values.forEach { $0.pause() }
    }

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        updateCurrentPage()
    }

    func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
        updateCurrentPage()
    }

    private func addImage(urlText: String, to page: UIView) {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFill
        imageView.clipsToBounds = true
        page.addSubview(imageView)
        imageView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        if let url = URL(string: urlText), !urlText.isEmpty {
            imageView.kf.setImage(with: url)
        }
    }

    private func addVideo(urlText: String, to page: UIView, index: Int) {
        guard let url = URL(string: urlText), !urlText.isEmpty else {
            addImage(urlText: "", to: page)
            return
        }
        let player = AVPlayer(url: url)
        players[index] = player
        let playerView = MaterialPlayerLayerView()
        playerView.configure(player: player)
        playerViews[index] = playerView
        page.addSubview(playerView)
        playerView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(videoDidEnd(_:)),
            name: .AVPlayerItemDidPlayToEndTime,
            object: player.currentItem
        )
    }

    private func layoutPages() {
        let size = bounds.size
        guard size.width > 0, size.height > 0 else { return }
        for (index, page) in scrollView.subviews.enumerated() {
            page.frame = CGRect(x: CGFloat(index) * size.width, y: 0, width: size.width, height: size.height)
        }
        scrollView.contentSize = CGSize(width: size.width * CGFloat(renderedMedia.count), height: size.height)
        scrollView.contentOffset = CGPoint(x: CGFloat(renderedPage) * size.width, y: 0)
    }

    private func updateCurrentPage() {
        guard bounds.width > 0 else { return }
        let rawPage = Int(round(scrollView.contentOffset.x / bounds.width))
        let page = MaterialCarouselIndexMapper.normalizedRenderedPage(rawPage, mediaCount: media.count)
        if media.count > 1 {
            if page != rawPage {
                scrollView.setContentOffset(CGPoint(x: CGFloat(page) * bounds.width, y: 0), animated: false)
            }
            pageControl.currentPage = MaterialCarouselIndexMapper.logicalPage(renderedPage: page, mediaCount: media.count)
        } else {
            pageControl.currentPage = 0
        }
        renderedPage = page
        playCurrentPageIfNeeded()
    }

    private func playCurrentPageIfNeeded() {
        stopTimer()
        players.forEach { index, player in
            if index == renderedPage {
                player.seek(to: .zero)
                player.play()
                playerViews[index]?.setPlaying(true)
            } else {
                player.pause()
                playerViews[index]?.setPlaying(false)
            }
        }
        guard renderedMedia.indices.contains(renderedPage) else { return }
        if renderedMedia[renderedPage].type == 1 {
            startImageTimer()
        }
    }

    private func startImageTimer() {
        guard media.count > 1 else { return }
        timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: false) { [weak self] _ in
            self?.advancePage()
        }
    }

    private func stopTimer() {
        timer?.invalidate()
        timer = nil
    }

    @objc private func videoDidEnd(_ notification: Notification) {
        guard players[renderedPage]?.currentItem === notification.object as? AVPlayerItem else { return }
        advancePage()
    }

    private func advancePage() {
        guard media.count > 1, bounds.width > 0 else { return }
        let nextPage = renderedPage + 1
        scrollView.setContentOffset(CGPoint(x: CGFloat(nextPage) * bounds.width, y: 0), animated: true)
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { [weak self] in
            self?.playCurrentPageIfNeeded()
        }
    }
}

/// AVPlayerLayer 容器。
/// 承载 AVPlayerLayer 的视频播放容器。
private final class MaterialPlayerLayerView: UIView {
    override class var layerClass: AnyClass { AVPlayerLayer.self }
    var playerLayer: AVPlayerLayer { layer as! AVPlayerLayer }
    private let controlButton = UIButton(type: .system)
    private weak var player: AVPlayer?
    private var hideWorkItem: DispatchWorkItem?

    override init(frame: CGRect) {
        super.init(frame: frame)
        controlButton.tintColor = .white
        controlButton.backgroundColor = UIColor.black.withAlphaComponent(0.5)
        controlButton.layer.cornerRadius = 24
        controlButton.addTarget(self, action: #selector(controlTapped), for: .touchUpInside)
        addSubview(controlButton)
        addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(showControls)))
        controlButton.snp.makeConstraints { make in make.center.equalToSuperview(); make.size.equalTo(48) }
    }

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

    func configure(player: AVPlayer) {
        self.player = player
        playerLayer.player = player
        playerLayer.videoGravity = .resizeAspect
        setPlaying(false)
    }

    func setPlaying(_ playing: Bool) {
        controlButton.setImage(UIImage(systemName: playing ? "pause.fill" : "play.fill"), for: .normal)
        if playing {
            scheduleHide()
        } else {
            hideWorkItem?.cancel()
            controlButton.isHidden = false
        }
    }

    @objc private func controlTapped() {
        guard let player else { return }
        if player.timeControlStatus == .playing {
            player.pause()
            setPlaying(false)
        } else {
            player.play()
            setPlaying(true)
        }
    }

    @objc private func showControls() {
        controlButton.isHidden = false
        if player?.timeControlStatus == .playing { scheduleHide() }
    }

    private func scheduleHide() {
        hideWorkItem?.cancel()
        controlButton.isHidden = false
        let work = DispatchWorkItem { [weak self] in self?.controlButton.isHidden = true }
        hideWorkItem = work
        DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: work)
    }
}

/// 素材详情基础信息区。
/// 素材详情的基础信息区块。
private final class MaterialDetailInfoSection: UIView {
    private let titleLabel = UILabel()
    private let listingBadge = UILabel()
    private let tagStack = UIStackView()
    private let statsStack = UIStackView()
    private let downloadStat = MaterialDetailStatView(iconName: "material_ic_download_count")
    private let likeStat = MaterialDetailStatView(iconName: "sample_ic_like_count")
    private let collectStat = MaterialDetailStatView(iconName: "sample_ic_collect_count")
    private var statsTopConstraint: Constraint?

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .white
        titleLabel.font = .systemFont(ofSize: 20, weight: .bold)
        titleLabel.textColor = UIColor(hex: 0x2E3746)
        titleLabel.numberOfLines = 0
        listingBadge.font = .systemFont(ofSize: 12)
        listingBadge.layer.cornerRadius = 4
        listingBadge.clipsToBounds = true
        listingBadge.textAlignment = .center
        tagStack.axis = .horizontal
        tagStack.spacing = 8
        tagStack.alignment = .center
        statsStack.axis = .horizontal
        statsStack.spacing = 16
        [downloadStat, likeStat, collectStat].forEach(statsStack.addArrangedSubview)

        addSubview(titleLabel)
        addSubview(listingBadge)
        addSubview(tagStack)
        addSubview(statsStack)
        titleLabel.snp.makeConstraints { make in
            make.top.leading.equalToSuperview().offset(16)
            make.trailing.lessThanOrEqualTo(listingBadge.snp.leading).offset(-12)
        }
        listingBadge.snp.makeConstraints { make in
            make.trailing.equalToSuperview().inset(16)
            make.centerY.equalTo(titleLabel)
            make.height.equalTo(24)
            make.width.greaterThanOrEqualTo(54)
        }
        tagStack.snp.makeConstraints { make in
            make.top.equalTo(titleLabel.snp.bottom).offset(12)
            make.leading.trailing.equalToSuperview().inset(16)
        }
        statsStack.snp.makeConstraints { make in
            statsTopConstraint = make.top.equalTo(tagStack.snp.bottom).offset(12).constraint
            make.leading.equalToSuperview().offset(16)
            make.trailing.lessThanOrEqualToSuperview().inset(16)
            make.bottom.equalToSuperview().inset(16)
        }
    }

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

    func apply(detail: MaterialDetail) {
        titleLabel.text = detail.name ?? ""
        let listed = detail.listingStatus == 1
        listingBadge.text = listed ? "已上架" : "未上架"
        let color = listed ? UIColor(hex: 0x22C55E) : AppColor.textSecondary
        listingBadge.textColor = color
        listingBadge.backgroundColor = color.withAlphaComponent(0.1)
        tagStack.arrangedSubviews.forEach { $0.removeFromSuperview() }
        let tags = detail.materialTag ?? []
        tags.forEach { tagStack.addArrangedSubview(makeTag($0.name)) }
        if !tags.isEmpty {
            tagStack.addArrangedSubview(UIView())
        }
        tagStack.isHidden = tags.isEmpty
        statsTopConstraint?.update(offset: tags.isEmpty ? 0 : 12)
        downloadStat.setCount(detail.downloadCount)
        likeStat.setCount(detail.likesCount)
        collectStat.setCount(detail.collectCount)
    }

    private func makeTag(_ title: String) -> UILabel {
        let label = MaterialDetailTagLabel(horizontalInset: 6)
        label.text = title
        label.font = .systemFont(ofSize: 12)
        label.textColor = AppColor.primary
        label.textAlignment = .center
        label.backgroundColor = UIColor(hex: 0xEFF6FF)
        label.layer.cornerRadius = 4
        label.clipsToBounds = true
        label.setContentHuggingPriority(.required, for: .horizontal)
        label.setContentCompressionResistancePriority(.required, for: .horizontal)
        label.snp.makeConstraints { make in
            make.height.equalTo(22)
        }
        return label
    }
}

/// 素材上传人信息区。
/// 素材详情的上传人信息区块。
private final class MaterialDetailUploaderSection: UIView {
    private let titleLabel = UILabel()
    private let avatarView = UIImageView()
    private let nameLabel = UILabel()
    private let tagStack = UIStackView()
    private let descriptionLabel = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .white
        titleLabel.text = "上传人"
        titleLabel.font = .systemFont(ofSize: 16, weight: .bold)
        titleLabel.textColor = AppColor.textPrimary
        avatarView.contentMode = .scaleAspectFill
        avatarView.clipsToBounds = true
        avatarView.layer.cornerRadius = 24
        avatarView.backgroundColor = UIColor(hex: 0xF5F5F5)
        nameLabel.font = .systemFont(ofSize: 14, weight: .medium)
        nameLabel.textColor = UIColor(hex: 0x002255)
        descriptionLabel.font = .systemFont(ofSize: 14)
        descriptionLabel.textColor = UIColor(hex: 0x7B8EAA)
        descriptionLabel.numberOfLines = 0
        tagStack.axis = .horizontal
        tagStack.spacing = 8

        addSubview(titleLabel)
        addSubview(avatarView)
        addSubview(nameLabel)
        addSubview(tagStack)
        addSubview(descriptionLabel)
        titleLabel.snp.makeConstraints { make in
            make.top.leading.trailing.equalToSuperview().inset(16)
        }
        avatarView.snp.makeConstraints { make in
            make.top.equalTo(titleLabel.snp.bottom).offset(12)
            make.leading.equalToSuperview().offset(16)
            make.size.equalTo(48)
            make.bottom.lessThanOrEqualToSuperview().inset(16)
        }
        nameLabel.snp.makeConstraints { make in
            make.top.equalTo(avatarView)
            make.leading.equalTo(avatarView.snp.trailing).offset(12)
        }
        tagStack.snp.makeConstraints { make in
            make.leading.equalTo(nameLabel.snp.trailing).offset(8)
            make.centerY.equalTo(nameLabel)
            make.trailing.lessThanOrEqualToSuperview().inset(16)
        }
        descriptionLabel.snp.makeConstraints { make in
            make.top.equalTo(nameLabel.snp.bottom).offset(4)
            make.leading.equalTo(nameLabel)
            make.trailing.equalToSuperview().inset(16)
            make.bottom.equalToSuperview().inset(16)
        }
    }

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

    func apply(detail: MaterialDetail) {
        nameLabel.text = detail.uploaderName ?? ""
        descriptionLabel.text = detail.uploaderDescription ?? ""
        tagStack.arrangedSubviews.forEach { $0.removeFromSuperview() }
        if detail.platformCertification {
            tagStack.addArrangedSubview(makeTag("平台认证"))
        }
        if detail.scenicCertification {
            tagStack.addArrangedSubview(makeTag("景区认证"))
        }
        if let urlText = detail.uploaderAvatar, let url = URL(string: urlText), !urlText.isEmpty {
            avatarView.kf.setImage(with: url, placeholder: UIImage(systemName: "person.crop.circle.fill"))
        } else {
            avatarView.image = UIImage(systemName: "person.crop.circle.fill")
            avatarView.tintColor = AppColor.textTertiary
        }
    }

    private func makeTag(_ title: String) -> UILabel {
        let label = MaterialDetailTagLabel(horizontalInset: 6)
        label.text = title
        label.textColor = .white
        label.font = .systemFont(ofSize: 8)
        label.textAlignment = .center
        label.backgroundColor = AppColor.primary
        label.layer.cornerRadius = 4
        label.clipsToBounds = true
        label.snp.makeConstraints { make in
            make.height.equalTo(16)
        }
        return label
    }
}

/// 为详情页标签文本提供固定水平内边距，使背景宽度随内容自适应。
private final class MaterialDetailTagLabel: UILabel {
    private let horizontalInset: CGFloat

    init(horizontalInset: CGFloat) {
        self.horizontalInset = horizontalInset
        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.insetBy(dx: horizontalInset, dy: 0))
    }

    override var intrinsicContentSize: CGSize {
        let size = super.intrinsicContentSize
        return CGSize(width: size.width + horizontalInset * 2, height: size.height)
    }
}

/// 素材审核信息区。
/// 素材详情的审核信息区块。
private final class MaterialDetailReviewSection: UIView {
    private let titleLabel = UILabel()
    private let stack = UIStackView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .white
        titleLabel.text = "审核信息"
        titleLabel.font = .systemFont(ofSize: 14, weight: .bold)
        titleLabel.textColor = .black
        stack.axis = .vertical
        stack.spacing = 0
        addSubview(titleLabel)
        addSubview(stack)
        titleLabel.snp.makeConstraints { make in
            make.top.leading.trailing.equalToSuperview().inset(16)
        }
        stack.snp.makeConstraints { make in
            make.top.equalTo(titleLabel.snp.bottom).offset(12)
            make.leading.trailing.bottom.equalToSuperview().inset(16)
        }
    }

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

    func apply(detail: MaterialDetail) {
        stack.arrangedSubviews.forEach { $0.removeFromSuperview() }
        stack.addArrangedSubview(MaterialInfoRow(label: "审核人", value: detail.reviewer ?? "--"))
        stack.addArrangedSubview(separator())
        stack.addArrangedSubview(MaterialInfoRow(label: "审核时间", value: detail.reviewTime ?? "--"))
        stack.addArrangedSubview(separator())
        stack.addArrangedSubview(MaterialStatusRow(status: detail.status))
        stack.addArrangedSubview(separator())
        stack.addArrangedSubview(MaterialInfoRow(label: "审核备注", value: detail.reviewNotes ?? "--", valueColor: UIColor(hex: 0x4B5563), valueFont: .systemFont(ofSize: 12)))
    }

    private func separator() -> UIView {
        let view = UIView()
        view.backgroundColor = UIColor(hex: 0xEEEEEE)
        view.snp.makeConstraints { make in
            make.height.equalTo(1)
        }
        return view
    }
}

/// 详情统计图标与数字。
/// 素材详情中的统计指标视图。
private final class MaterialDetailStatView: UIView {
    private let iconView = UIImageView()
    private let countLabel = UILabel()

    init(iconName: String? = nil, systemIconName: String? = nil) {
        super.init(frame: .zero)
        if let iconName {
            iconView.image = UIImage(named: iconName)
        } else if let systemIconName {
            iconView.image = UIImage(systemName: systemIconName)
        }
        iconView.tintColor = UIColor(hex: 0x6B7280)
        iconView.contentMode = .scaleAspectFit
        countLabel.font = .systemFont(ofSize: 14)
        countLabel.textColor = UIColor(hex: 0x6B7280)
        addSubview(iconView)
        addSubview(countLabel)
        iconView.snp.makeConstraints { make in
            make.leading.centerY.equalToSuperview()
            make.size.equalTo(16)
        }
        countLabel.snp.makeConstraints { make in
            make.leading.equalTo(iconView.snp.trailing).offset(4)
            make.trailing.centerY.equalToSuperview()
        }
    }

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

    func setCount(_ count: Int) {
        countLabel.text = MaterialDisplayFormatter.formatCount(count)
    }
}

/// 素材详情普通信息行。
/// 标题和值组成的信息行。
private final class MaterialInfoRow: UIView {
    private let label = UILabel()
    private let valueLabel = UILabel()

    init(label: String, value: String, valueColor: UIColor = .black, valueFont: UIFont = .systemFont(ofSize: 14, weight: .medium)) {
        super.init(frame: .zero)
        self.label.text = label
        self.label.font = .systemFont(ofSize: 14)
        self.label.textColor = UIColor(hex: 0x2E3746)
        valueLabel.text = value
        valueLabel.font = valueFont
        valueLabel.textColor = valueColor
        valueLabel.textAlignment = .right
        valueLabel.numberOfLines = 1
        addSubview(self.label)
        addSubview(valueLabel)
        snp.makeConstraints { make in
            make.height.equalTo(44)
        }
        self.label.snp.makeConstraints { make in
            make.leading.centerY.equalToSuperview()
        }
        valueLabel.snp.makeConstraints { make in
            make.leading.greaterThanOrEqualTo(self.label.snp.trailing).offset(12)
            make.trailing.centerY.equalToSuperview()
        }
    }

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

/// 素材审核状态行。
/// 素材详情中展示上架状态的信息行。
private final class MaterialStatusRow: UIView {
    private let label = UILabel()
    private let badge = MaterialStatusBadgeView()

    init(status: Int) {
        super.init(frame: .zero)
        label.text = "审核状态"
        label.font = .systemFont(ofSize: 14)
        label.textColor = UIColor(hex: 0x2E3746)
        badge.apply(status: status)
        addSubview(label)
        addSubview(badge)
        snp.makeConstraints { make in
            make.height.equalTo(44)
        }
        label.snp.makeConstraints { make in
            make.leading.centerY.equalToSuperview()
        }
        badge.snp.makeConstraints { make in
            make.trailing.centerY.equalToSuperview()
            make.height.equalTo(24)
        }
    }

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