//
//  WildReportSupplementEvidenceViewController.swift
//  suixinkan
//

import PhotosUI
import SnapKit
import UIKit

/// 补充证据页面，允许为已有举报追加说明、图片和视频证据。
final class WildReportSupplementEvidenceViewController: BaseViewController {
    private let viewModel: WildReportSupplementEvidenceViewModel
    private let api: any WildPhotographerReportServing
    private let uploader: any WildReportAttachmentUploading
    private let onSupplementSuccess: (() -> Void)?

    private let scrollView = UIScrollView()
    private let contentStack = UIStackView()
    private let textView = UITextView()
    private let placeholderLabel = UILabel()
    private let countLabel = UILabel()
    private let submitButton = UIButton(type: .system)

    private var pickerTarget: WildReportPickerTarget = .image
    private weak var activeInputView: UIView?
    private var isShowingSubmitLoading = false

    init(
        record: WildReportRecord,
        homeViewModel: WildPhotographerReportHomeViewModel,
        api: (any WildPhotographerReportServing)? = nil,
        uploader: (any WildReportAttachmentUploading)? = nil,
        onSupplementSuccess: (() -> Void)? = nil
    ) {
        self.viewModel = WildReportSupplementEvidenceViewModel(record: record, homeViewModel: homeViewModel)
        self.api = api ?? NetworkServices.shared.wildPhotographerReportAPI
        self.uploader = uploader ?? NetworkServices.shared.ossUploadService
        self.onSupplementSuccess = onSupplementSuccess
        super.init(nibName: nil, bundle: nil)
    }

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

    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    override func setupNavigationBar() {
        title = "补充证据"
    }

    override func setupUI() {
        view.backgroundColor = UIColor(hex: 0xF8FAFF)
        scrollView.keyboardDismissMode = .interactive
        scrollView.showsVerticalScrollIndicator = false
        contentStack.axis = .vertical
        contentStack.spacing = 14

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

        placeholderLabel.text = "请补充新的线索说明..."
        placeholderLabel.font = .systemFont(ofSize: 15)
        placeholderLabel.textColor = UIColor(hex: 0x9CA3AF)

        countLabel.font = .systemFont(ofSize: 14)
        countLabel.textColor = UIColor(hex: 0x6B7280)
        countLabel.textAlignment = .right

        submitButton.setTitle("提交补充证据", for: .normal)
        submitButton.titleLabel?.font = .systemFont(ofSize: 18, weight: .bold)
        submitButton.setTitleColor(.white, for: .normal)
        submitButton.backgroundColor = AppColor.primary
        submitButton.layer.cornerRadius = 14
        submitButton.addTarget(self, action: #selector(submitTapped), for: .touchUpInside)

        view.addSubview(scrollView)
        scrollView.addSubview(contentStack)
        view.addSubview(submitButton)

        let dismissTap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
        dismissTap.cancelsTouchesInView = false
        dismissTap.delegate = self
        scrollView.addGestureRecognizer(dismissTap)
        registerKeyboardNotifications()
        rebuildContent()
    }

    override func setupConstraints() {
        submitButton.snp.makeConstraints { make in
            make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(18)
            make.bottom.equalTo(view.safeAreaLayoutGuide).inset(12)
            make.height.equalTo(52)
        }
        scrollView.snp.makeConstraints { make in
            make.top.leading.trailing.equalTo(view.safeAreaLayoutGuide)
            make.bottom.equalTo(submitButton.snp.top).offset(-12)
        }
        contentStack.snp.makeConstraints { make in
            make.edges.equalTo(scrollView.contentLayoutGuide).inset(UIEdgeInsets(top: 16, left: 18, bottom: 28, right: 18))
            make.width.equalTo(scrollView.frameLayoutGuide).offset(-36)
        }
    }

    override func bindActions() {
        viewModel.onStateChange = { [weak self] in
            Task { @MainActor in
                guard let self else { return }
                self.updateSubmitLoading()
                if self.textView.isFirstResponder {
                    self.updateTextInputState()
                    self.updateSubmitButton()
                } else {
                    self.rebuildContent()
                }
            }
        }
        viewModel.onShowMessage = { [weak self] message in
            Task { @MainActor in self?.showToast(message) }
        }
        viewModel.onSubmitSuccess = { [weak self] in
            Task { @MainActor in
                guard let self else { return }
                self.onSupplementSuccess?()
                self.showToast("补充证据已提交")
                self.navigationController?.popViewController(animated: true)
            }
        }
    }

    @MainActor
    private func rebuildContent() {
        contentStack.arrangedSubviews.forEach { view in
            contentStack.removeArrangedSubview(view)
            view.removeFromSuperview()
        }
        contentStack.addArrangedSubview(makeTextCard())
        contentStack.addArrangedSubview(makeUploadCard(
            icon: "photo.fill",
            title: "上传图片",
            subtitle: "支持 JPG、PNG 格式，最多 9 张",
            attachments: viewModel.images,
            maxCount: 9,
            kind: .image
        ))
        contentStack.addArrangedSubview(makeUploadCard(
            icon: "video.fill",
            title: "上传视频",
            subtitle: "支持 MP4 格式，最多 3 段",
            attachments: viewModel.videos,
            maxCount: 3,
            kind: .video
        ))
        updateSubmitButton()
    }

    private func makeTextCard() -> UIView {
        let card = cardView(spacing: 10)
        card.stack.addArrangedSubview(WildReportUI.label("补充说明", font: .systemFont(ofSize: 17, weight: .bold), color: AppColor.textPrimary))
        textView.text = viewModel.text

        let inputContainer = UIView()
        inputContainer.backgroundColor = UIColor(hex: 0xFBFCFE)
        inputContainer.layer.cornerRadius = 12
        inputContainer.layer.borderWidth = 1
        inputContainer.layer.borderColor = UIColor(hex: 0xCDD5E1).cgColor
        inputContainer.addSubview(textView)
        inputContainer.addSubview(placeholderLabel)
        inputContainer.addSubview(countLabel)

        textView.snp.remakeConstraints { make in
            make.edges.equalToSuperview()
            make.height.greaterThanOrEqualTo(132)
        }
        placeholderLabel.snp.remakeConstraints { make in
            make.top.equalToSuperview().offset(18)
            make.leading.equalToSuperview().offset(14)
            make.trailing.lessThanOrEqualToSuperview().inset(14)
        }
        countLabel.snp.remakeConstraints { make in
            make.trailing.bottom.equalToSuperview().inset(12)
        }
        card.stack.addArrangedSubview(inputContainer)
        updateTextInputState()
        return card
    }

    private func makeUploadCard(
        icon: String,
        title: String,
        subtitle: String,
        attachments: [WildReportAttachment],
        maxCount: Int,
        kind: WildReportAttachmentKind
    ) -> UIView {
        let card = cardView(spacing: 12)
        let header = UIStackView()
        header.axis = .horizontal
        header.alignment = .center
        header.spacing = 10

        let iconView = UIImageView(image: UIImage(systemName: icon))
        iconView.tintColor = AppColor.primary
        iconView.contentMode = .scaleAspectFit
        iconView.snp.makeConstraints { make in
            make.size.equalTo(26)
        }

        let textStack = UIStackView()
        textStack.axis = .vertical
        textStack.spacing = 4
        textStack.addArrangedSubview(WildReportUI.label(title, font: .systemFont(ofSize: 16, weight: .bold), color: AppColor.textPrimary))
        textStack.addArrangedSubview(WildReportUI.label(subtitle, font: .systemFont(ofSize: 12), color: AppColor.textSecondary, lines: 0))

        header.addArrangedSubview(iconView)
        header.addArrangedSubview(textStack)
        header.addArrangedSubview(UIView())
        card.stack.addArrangedSubview(header)

        let scroll = UIScrollView()
        scroll.showsHorizontalScrollIndicator = false
        let tiles = UIStackView()
        tiles.axis = .horizontal
        tiles.spacing = 10
        scroll.addSubview(tiles)
        tiles.snp.makeConstraints { make in
            make.edges.equalTo(scroll.contentLayoutGuide).inset(UIEdgeInsets(top: 2, left: 0, bottom: 2, right: 0))
            make.height.equalTo(scroll.frameLayoutGuide).offset(-4)
        }

        attachments.forEach { attachment in
            tiles.addArrangedSubview(WildReportAttachmentTileView(
                attachment: attachment,
                tileSize: 72,
                onPreview: { [weak self] in self?.previewAttachment(attachment) },
                onRemove: { [weak self] in self?.viewModel.removeAttachment(attachment) }
            ))
        }

        if canAddAttachment(kind: kind, currentCount: attachments.count, maxCount: maxCount) {
            tiles.addArrangedSubview(WildReportAddAttachmentTileView(
                tileSize: 72,
                borderColor: AppColor.primary,
                iconColor: AppColor.primary
            ) { [weak self] in
                self?.presentMediaPicker(for: WildReportPickerTarget(kind: kind))
            })
        }

        scroll.snp.makeConstraints { make in
            make.height.equalTo(76)
        }
        card.stack.addArrangedSubview(scroll)
        return card
    }

    private func cardView(spacing: CGFloat) -> WildReportCardView {
        let card = WildReportCardView(spacing: spacing, inset: 16)
        card.layer.cornerRadius = 16
        card.layer.borderColor = AppColor.cardOutline.cgColor
        return card
    }

    private func updateTextInputState() {
        placeholderLabel.isHidden = !viewModel.text.isEmpty
        countLabel.text = "\(viewModel.text.count)/500"
    }

    private func updateSubmitButton() {
        submitButton.setTitle("提交补充证据", for: .normal)
        submitButton.isEnabled = !viewModel.isSubmitting
        submitButton.alpha = viewModel.isSubmitting ? 0.78 : 1
    }

    @MainActor
    private func updateSubmitLoading() {
        if viewModel.isSubmitting {
            guard !isShowingSubmitLoading else { return }
            isShowingSubmitLoading = true
            showLoading()
        } else if isShowingSubmitLoading {
            isShowingSubmitLoading = false
            hideLoading()
        }
    }

    private func canAddAttachment(kind: WildReportAttachmentKind, currentCount: Int, maxCount: Int) -> Bool {
        let ownRemaining = max(0, maxCount - currentCount)
        let evidenceRemaining = max(0, 9 - viewModel.images.count - viewModel.videos.count)
        switch kind {
        case .image:
            return min(ownRemaining, evidenceRemaining) > 0
        case .video:
            return min(ownRemaining, evidenceRemaining) > 0
        case .payment:
            return false
        }
    }

    private func presentMediaPicker(for target: WildReportPickerTarget) {
        dismissKeyboard()
        let remaining = remainingSelectionCount(for: target)
        guard remaining > 0 else {
            showToast(target == .video ? "补充视频最多上传3段" : "补充证据最多上传9项")
            return
        }
        pickerTarget = target
        var configuration = PHPickerConfiguration(photoLibrary: .shared())
        configuration.selectionLimit = remaining
        configuration.filter = target == .video ? .videos : .images
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = self
        present(picker, animated: true)
    }

    private func remainingSelectionCount(for target: WildReportPickerTarget) -> Int {
        switch target {
        case .image:
            return max(0, 9 - viewModel.images.count - viewModel.videos.count)
        case .video:
            return max(0, min(3 - viewModel.videos.count, 9 - viewModel.images.count - viewModel.videos.count))
        case .payment:
            return 0
        }
    }

    private func previewAttachment(_ attachment: WildReportAttachment) {
        guard let item = MediaPreviewItem(wildReportAttachment: attachment) else {
            showToast("当前附件暂无本地预览")
            return
        }
        presentMediaPreview(items: [item], startIndex: 0)
    }

    @objc private func submitTapped() {
        Task {
            await viewModel.submit(
                api: api,
                uploader: uploader,
                scenicId: AppStore.shared.session.currentScenicId
            )
        }
    }

    @objc private func dismissKeyboard() {
        view.endEditing(true)
    }

    private func registerKeyboardNotifications() {
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(keyboardWillChangeFrame(_:)),
            name: UIResponder.keyboardWillChangeFrameNotification,
            object: nil
        )
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(keyboardWillHide(_:)),
            name: UIResponder.keyboardWillHideNotification,
            object: nil
        )
    }

    @objc private func keyboardWillChangeFrame(_ notification: Notification) {
        guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
        let keyboardFrameInView = view.convert(keyboardFrame, from: nil)
        let overlap = max(0, view.bounds.maxY - keyboardFrameInView.minY)
        updateScrollInsets(bottom: overlap + 12, notification: notification)
        scrollActiveInputIntoView(animated: true)
    }

    @objc private func keyboardWillHide(_ notification: Notification) {
        updateScrollInsets(bottom: 0, notification: notification)
    }

    private func updateScrollInsets(bottom: CGFloat, notification: Notification) {
        let duration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval ?? 0.25
        let curveRaw = notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt ?? UIView.AnimationOptions.curveEaseInOut.rawValue
        let options = UIView.AnimationOptions(rawValue: curveRaw << 16)
        UIView.animate(withDuration: duration, delay: 0, options: options) {
            self.scrollView.contentInset.bottom = bottom
            self.scrollView.verticalScrollIndicatorInsets.bottom = bottom
        }
    }

    private func scrollActiveInputIntoView(animated: Bool) {
        guard let activeInputView else { return }
        view.layoutIfNeeded()
        let rect = activeInputView.convert(activeInputView.bounds, to: scrollView).insetBy(dx: 0, dy: -24)
        scrollView.scrollRectToVisible(rect, animated: animated)
    }
}

extension WildReportSupplementEvidenceViewController: PHPickerViewControllerDelegate {
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        picker.dismiss(animated: true)
        guard !results.isEmpty else { return }
        let target = pickerTarget
        Task {
            do {
                let attachments = try await WildReportLocalMediaLoader.load(
                    results: results,
                    target: target,
                    titlePrefix: target == .video ? "补充视频" : "补充图片"
                )
                await MainActor.run {
                    switch target {
                    case .image:
                        viewModel.addImages(attachments)
                    case .video:
                        viewModel.addVideos(attachments)
                    case .payment:
                        break
                    }
                }
            } catch {
                await MainActor.run { showToast(error.localizedDescription) }
            }
        }
    }
}

extension WildReportSupplementEvidenceViewController: UITextViewDelegate {
    func textViewDidBeginEditing(_ textView: UITextView) {
        activeInputView = textView
        DispatchQueue.main.async { [weak self] in self?.scrollActiveInputIntoView(animated: true) }
    }

    func textViewDidChange(_ textView: UITextView) {
        viewModel.updateText(textView.text)
        if textView.text != viewModel.text {
            textView.text = viewModel.text
        }
        updateTextInputState()
    }

    func textViewDidEndEditing(_ textView: UITextView) {
        if activeInputView === textView {
            activeInputView = nil
        }
    }
}

extension WildReportSupplementEvidenceViewController: UIGestureRecognizerDelegate {
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        var touchedView = touch.view
        while let currentView = touchedView {
            if currentView is UIControl || currentView is UITextView {
                return false
            }
            touchedView = currentView.superview
        }
        return true
    }
}
