//
//  WildReportCommonViews.swift
//  suixinkan
//

import AVFoundation
import PhotosUI
import SnapKit
import UIKit
import UniformTypeIdentifiers

/// 举报摄影师模块 UI 工具，统一卡片、标签和按钮样式。
enum WildReportUI {
    static func label(_ text: String, font: UIFont, color: UIColor, lines: Int = 1) -> UILabel {
        let label = UILabel()
        label.text = text
        label.font = font
        label.textColor = color
        label.numberOfLines = lines
        return label
    }

    static func iconButton(title: String, imageName: String, style: AppButton.Style = .primary) -> UIButton {
        let button = UIButton(type: .system)
        button.titleLabel?.font = .app(.subtitle)
        button.setTitle(title, for: .normal)
        button.setImage(UIImage(systemName: imageName), for: .normal)
        button.tintColor = style == .primary ? .white : AppColor.primary
        button.setTitleColor(style == .primary ? .white : AppColor.primary, for: .normal)
        button.backgroundColor = style == .primary ? AppColor.primary : AppColor.primaryLight
        button.layer.cornerRadius = AppRadius.md
        button.setConfigurationContentInsets(
            NSDirectionalEdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 12)
        )
        button.configuration?.imagePlacement = .leading
        button.configuration?.imagePadding = 4
        return button
    }
}

/// 举报模块白底卡片容器。
final class WildReportCardView: UIView {
    let stack = UIStackView()

    init(spacing: CGFloat = AppSpacing.sm, inset: CGFloat = AppSpacing.md) {
        super.init(frame: .zero)
        backgroundColor = .white
        layer.cornerRadius = AppRadius.lg
        layer.borderWidth = 1
        layer.borderColor = AppColor.cardOutline.cgColor

        stack.axis = .vertical
        stack.spacing = max(0, spacing - AppSpacing.xxs)
        addSubview(stack)
        stack.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(inset)
        }
    }

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

/// 举报模块状态标签。
final class WildReportStatusView: UILabel {
    override init(frame: CGRect) {
        super.init(frame: frame)
        font = .app(.captionMedium)
        textAlignment = .center
        layer.cornerRadius = 12
        clipsToBounds = true
    }

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

    func apply(status: WildReportStatus) {
        text = status.rawValue
        textColor = status.displayColor
        backgroundColor = status.backgroundColor
    }
}

/// 举报模块左右信息行。
final class WildReportInfoRowView: UIView {
    private let titleLabel = UILabel()
    private let valueLabel = UILabel()

    init(title: String, value: String) {
        super.init(frame: .zero)
        titleLabel.font = .app(.body)
        titleLabel.textColor = AppColor.textSecondary
        titleLabel.text = title
        valueLabel.font = .app(.bodyMedium)
        valueLabel.textColor = AppColor.textPrimary
        valueLabel.textAlignment = .right
        valueLabel.numberOfLines = 0
        valueLabel.text = value

        addSubview(titleLabel)
        addSubview(valueLabel)
        titleLabel.snp.makeConstraints { make in
            make.leading.top.equalToSuperview()
            make.width.greaterThanOrEqualTo(76)
            make.bottom.lessThanOrEqualToSuperview()
        }
        valueLabel.snp.makeConstraints { make in
            make.leading.greaterThanOrEqualTo(titleLabel.snp.trailing).offset(AppSpacing.sm)
            make.trailing.top.bottom.equalToSuperview()
        }
    }

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

/// 举报模块附件占位 chip。
final class WildReportAttachmentChipView: UIView {
    private let titleLabel = UILabel()
    private let iconView = UIImageView()
    var onRemove: (() -> Void)?

    init(attachment: WildReportAttachment, removable: Bool = true) {
        super.init(frame: .zero)
        backgroundColor = AppColor.pageBackgroundSoft
        layer.cornerRadius = AppRadius.md
        layer.borderWidth = 1
        layer.borderColor = AppColor.cardOutline.cgColor

        iconView.image = UIImage(systemName: iconName(for: attachment.kind))
        iconView.tintColor = AppColor.primary
        titleLabel.text = attachment.title
        titleLabel.font = .app(.captionMedium)
        titleLabel.textColor = AppColor.textPrimary

        addSubview(iconView)
        addSubview(titleLabel)
        iconView.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(AppSpacing.sm)
            make.centerY.equalToSuperview()
            make.size.equalTo(18)
        }
        titleLabel.snp.makeConstraints { make in
            make.leading.equalTo(iconView.snp.trailing).offset(AppSpacing.xs)
            make.centerY.equalToSuperview()
            make.trailing.lessThanOrEqualToSuperview().inset(removable ? 34 : AppSpacing.sm)
        }

        if removable {
            let button = UIButton(type: .system)
            button.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal)
            button.tintColor = AppColor.textTertiary
            button.addTarget(self, action: #selector(removeTapped), for: .touchUpInside)
            addSubview(button)
            button.snp.makeConstraints { make in
                make.trailing.equalToSuperview().inset(AppSpacing.xs)
                make.centerY.equalToSuperview()
                make.size.equalTo(28)
            }
        }

        snp.makeConstraints { make in
            make.height.equalTo(40)
        }
    }

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

    private func iconName(for kind: WildReportAttachmentKind) -> String {
        switch kind {
        case .image: return "photo.fill"
        case .video: return "video.fill"
        case .payment: return "creditcard.fill"
        }
    }

    @objc private func removeTapped() {
        onRemove?()
    }
}

/// 举报模块本地媒体选择目标。
enum WildReportPickerTarget: Equatable {
    case image
    case video
    case payment

    init(kind: WildReportAttachmentKind) {
        switch kind {
        case .image: self = .image
        case .video: self = .video
        case .payment: self = .payment
        }
    }

    var attachmentKind: WildReportAttachmentKind {
        switch self {
        case .image: return .image
        case .video: return .video
        case .payment: return .payment
        }
    }

    var titlePrefix: String {
        switch self {
        case .image: return "现场图片"
        case .video: return "现场视频"
        case .payment: return "支付截图"
        }
    }

    var limitMessage: String {
        switch self {
        case .image: return "现场证据最多上传9项"
        case .video: return "现场视频最多上传3段"
        case .payment: return "支付截图最多上传3张"
        }
    }
}

/// 举报模块 PHPicker 结果加载器，将图片/视频保存为可预览和待上传的本地文件。
enum WildReportLocalMediaLoader {
    static func load(
        results: [PHPickerResult],
        target: WildReportPickerTarget,
        titlePrefix: String? = nil
    ) async throws -> [WildReportAttachment] {
        var attachments: [WildReportAttachment] = []
        for result in results {
            let attachment = target == .video
                ? try await loadVideo(from: result.itemProvider, target: target, titlePrefix: titlePrefix)
                : try await loadImage(from: result.itemProvider, target: target, titlePrefix: titlePrefix)
            attachments.append(attachment)
        }
        return attachments
    }

    private static func loadImage(
        from provider: NSItemProvider,
        target: WildReportPickerTarget,
        titlePrefix: String?
    ) async throws -> WildReportAttachment {
        try await withCheckedThrowingContinuation { continuation in
            guard provider.canLoadObject(ofClass: UIImage.self) else {
                continuation.resume(throwing: OSSUploadError.unsupportedFileType)
                return
            }
            provider.loadObject(ofClass: UIImage.self) { object, error in
                if let error {
                    continuation.resume(throwing: error)
                    return
                }
                guard let image = object as? UIImage,
                      let data = image.jpegData(compressionQuality: 0.9) else {
                    continuation.resume(throwing: OSSUploadError.emptyFile)
                    return
                }
                do {
                    let fileName = "report_image_\(UUID().uuidString).jpg"
                    let url = try write(data: data, fileName: fileName)
                    continuation.resume(returning: WildReportAttachment(
                        kind: target.attachmentKind,
                        title: titlePrefix ?? target.titlePrefix,
                        localFileURL: url,
                        fileName: fileName
                    ))
                } catch {
                    continuation.resume(throwing: error)
                }
            }
        }
    }

    private static func loadVideo(
        from provider: NSItemProvider,
        target: WildReportPickerTarget,
        titlePrefix: String?
    ) async throws -> WildReportAttachment {
        try await withCheckedThrowingContinuation { continuation in
            provider.loadFileRepresentation(forTypeIdentifier: UTType.movie.identifier) { url, error in
                if let error {
                    continuation.resume(throwing: error)
                    return
                }
                guard let url else {
                    continuation.resume(throwing: OSSUploadError.emptyFile)
                    return
                }
                do {
                    let ext = url.pathExtension.isEmpty ? "mp4" : url.pathExtension
                    let fileName = "report_video_\(UUID().uuidString).\(ext)"
                    let targetURL = try temporaryFileURL(fileName: fileName)
                    if FileManager.default.fileExists(atPath: targetURL.path) {
                        try FileManager.default.removeItem(at: targetURL)
                    }
                    try FileManager.default.copyItem(at: url, to: targetURL)
                    continuation.resume(returning: WildReportAttachment(
                        kind: target.attachmentKind,
                        title: titlePrefix ?? target.titlePrefix,
                        localFileURL: targetURL,
                        fileName: fileName
                    ))
                } catch {
                    continuation.resume(throwing: error)
                }
            }
        }
    }

    private static func write(data: Data, fileName: String) throws -> URL {
        let url = try temporaryFileURL(fileName: fileName)
        try data.write(to: url, options: .atomic)
        return url
    }

    private static func temporaryFileURL(fileName: String) throws -> URL {
        let directory = FileManager.default.temporaryDirectory.appendingPathComponent("wild_report_media", isDirectory: true)
        if !FileManager.default.fileExists(atPath: directory.path) {
            try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
        }
        return directory.appendingPathComponent(fileName)
    }
}

extension MediaPreviewItem {
    /// 从举报本地附件创建媒体预览资源项。
    init?(wildReportAttachment attachment: WildReportAttachment) {
        guard let url = attachment.localFileURL else { return nil }
        switch attachment.kind {
        case .image, .payment:
            self = .localImage(url: url)
        case .video:
            self = .localVideo(url: url)
        }
    }
}

/// 举报模块附件缩略 tile，优先展示本地图片或视频封面。
final class WildReportAttachmentTileView: UIControl {
    private let gradientLayer = CAGradientLayer()
    private let previewAction: () -> Void
    private let removeAction: () -> Void
    private let tileSize: CGFloat

    init(
        attachment: WildReportAttachment,
        tileSize: CGFloat = 58,
        onPreview: @escaping () -> Void,
        onRemove: @escaping () -> Void
    ) {
        self.previewAction = onPreview
        self.removeAction = onRemove
        self.tileSize = tileSize
        super.init(frame: .zero)
        layer.cornerRadius = 10
        clipsToBounds = false

        gradientLayer.cornerRadius = 10
        let colors: [UIColor] = attachment.kind == .video
            ? [UIColor(hex: 0xB7D8FF), UIColor(hex: 0x4C8FEF)]
            : [UIColor(hex: 0xCFE6FF), UIColor(hex: 0x7EB4FF)]
        gradientLayer.colors = colors.map(\.cgColor)
        gradientLayer.startPoint = CGPoint(x: 0, y: 0)
        gradientLayer.endPoint = CGPoint(x: 1, y: 1)
        layer.insertSublayer(gradientLayer, at: 0)

        let thumbnailView = UIImageView()
        thumbnailView.image = WildReportAttachmentThumbnailFactory.thumbnail(for: attachment)
        thumbnailView.contentMode = .scaleAspectFill
        thumbnailView.clipsToBounds = true
        thumbnailView.layer.cornerRadius = 10
        thumbnailView.isUserInteractionEnabled = false
        thumbnailView.isHidden = thumbnailView.image == nil
        addSubview(thumbnailView)
        thumbnailView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }

        let icon = UIImageView(image: UIImage(systemName: attachment.kind == .video ? "play.circle.fill" : "mountain.2.fill"))
        icon.tintColor = UIColor.white.withAlphaComponent(0.95)
        icon.contentMode = .scaleAspectFit
        icon.isHidden = attachment.kind != .video && thumbnailView.image != nil
        addSubview(icon)
        icon.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(attachment.kind == .video ? 30 : 26)
        }

        let removeButton = UIButton(type: .system)
        removeButton.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal)
        removeButton.setPreferredSymbolConfiguration(UIImage.SymbolConfiguration(pointSize: 17, weight: .semibold), forImageIn: .normal)
        removeButton.tintColor = UIColor(hex: 0x8D93A1)
        removeButton.backgroundColor = .white
        removeButton.layer.cornerRadius = 14
        removeButton.layer.shadowColor = UIColor.black.cgColor
        removeButton.layer.shadowOpacity = 0.10
        removeButton.layer.shadowRadius = 4
        removeButton.layer.shadowOffset = CGSize(width: 0, height: 2)
        removeButton.addTarget(self, action: #selector(removeTapped), for: .touchUpInside)
        addSubview(removeButton)
        removeButton.snp.makeConstraints { make in
            make.top.trailing.equalToSuperview().inset(-2)
            make.size.equalTo(34)
        }

        addTarget(self, action: #selector(previewTapped), for: .touchUpInside)
        snp.makeConstraints { make in
            make.size.equalTo(tileSize)
        }
    }

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

    override func layoutSubviews() {
        super.layoutSubviews()
        gradientLayer.frame = bounds
    }

    @objc private func previewTapped() {
        previewAction()
    }

    @objc private func removeTapped() {
        removeAction()
    }
}

/// 举报模块附件封面生成器，负责从本地图片或视频文件提取缩略图。
enum WildReportAttachmentThumbnailFactory {
    static func thumbnail(for attachment: WildReportAttachment) -> UIImage? {
        guard let url = attachment.localFileURL else { return nil }
        switch attachment.kind {
        case .image, .payment:
            return UIImage(contentsOfFile: url.path)
        case .video:
            return videoThumbnail(url: url)
        }
    }

    private static func videoThumbnail(url: URL) -> UIImage? {
        let asset = AVURLAsset(url: url)
        let generator = AVAssetImageGenerator(asset: asset)
        generator.appliesPreferredTrackTransform = true
        generator.maximumSize = CGSize(width: 160, height: 160)
        do {
            let cgImage = try generator.copyCGImage(at: CMTime(seconds: 0.1, preferredTimescale: 600), actualTime: nil)
            return UIImage(cgImage: cgImage)
        } catch {
            return nil
        }
    }
}

/// 举报模块添加附件 tile，白底虚线加号。
final class WildReportAddAttachmentTileView: UIControl {
    private let tapAction: () -> Void
    private let borderLayer = CAShapeLayer()
    private let tileSize: CGFloat

    init(
        tileSize: CGFloat = 58,
        borderColor: UIColor = UIColor(hex: 0xCDD5E1),
        iconColor: UIColor = UIColor(hex: 0x8D93A1),
        action: @escaping () -> Void
    ) {
        self.tapAction = action
        self.tileSize = tileSize
        super.init(frame: .zero)
        backgroundColor = .white
        layer.cornerRadius = 10

        borderLayer.strokeColor = borderColor.cgColor
        borderLayer.fillColor = UIColor.clear.cgColor
        borderLayer.lineWidth = 1
        borderLayer.lineDashPattern = [5, 4]
        layer.addSublayer(borderLayer)

        let icon = UIImageView(image: UIImage(systemName: "plus"))
        icon.tintColor = iconColor
        icon.contentMode = .scaleAspectFit
        addSubview(icon)
        icon.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(30)
        }

        addTarget(self, action: #selector(tapped), for: .touchUpInside)
        snp.makeConstraints { make in
            make.size.equalTo(tileSize)
        }
    }

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

    override func layoutSubviews() {
        super.layoutSubviews()
        borderLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: 10).cgPath
    }

    @objc private func tapped() {
        tapAction()
    }
}

/// 举报模块空状态视图。
final class WildReportEmptyView: UIView {
    init(text: String) {
        super.init(frame: .zero)
        let icon = UIImageView(image: UIImage(systemName: "tray"))
        icon.tintColor = AppColor.textTertiary
        let label = WildReportUI.label(text, font: .app(.body), color: AppColor.textSecondary, lines: 0)
        label.textAlignment = .center
        addSubview(icon)
        addSubview(label)
        icon.snp.makeConstraints { make in
            make.top.centerX.equalToSuperview()
            make.size.equalTo(42)
        }
        label.snp.makeConstraints { make in
            make.top.equalTo(icon.snp.bottom).offset(AppSpacing.sm)
            make.leading.trailing.bottom.equalToSuperview()
        }
    }

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