//
//  LNProfilePhotoWall.swift
//  Lanu
//
//  Created by OneeChan on 2025/11/30.
//

import Foundation
import UIKit
import SnapKit
import Combine

private class LNProfilePhotoWallMode {
    var url: String = ""
    var ratio: Double = 0.0
}


protocol LNProfilePhotoWallDelegate: AnyObject {
    func onProfilePhotoWall(view: LNProfilePhotoWall, contentHeightChanged height: CGFloat)
}


class LNProfilePhotoWall: UIView {
    private let emptyView = LNNoMoreDataView()
    private let columnCount = 2
    private var allPhotos: [LNProfilePhotoWallMode] = []
    private var columns: [[LNProfilePhotoWallMode]] = []
    private var tableViews: [LNNestedTableView] = []
    
    private(set) var contentHeight: CGFloat = 0.0 {
        didSet {
            self.delegate?.onProfilePhotoWall(view: self, contentHeightChanged: contentHeight)
        }
    }
    
    weak var delegate: LNProfilePhotoWallDelegate?
    weak var outerScrollView: LNNestedScrollViewDelegate? {
        didSet {
            tableViews.forEach { $0.observerDelegate = outerScrollView }
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        setupViews()
    }
    
    func update(_ urls: [String]) {
        allPhotos.removeAll()
        
        if urls.isEmpty {
            emptyView.showNoData()
        } else {
            emptyView.hide()
        }
        
        urls.forEach {
            let mode = LNProfilePhotoWallMode()
            mode.url = $0
            allPhotos.append(mode)
            
            SDWebImageManager.shared.loadImage(with: URL(string: $0), progress: nil)
            { [weak self] image, _, _, _, _, _ in
                guard let self else { return }
                guard let image else { return }
                mode.ratio = min(image.size.height / image.size.width, 3.0 / 2.0) // 最大宽高比 3:2
                self.resortModes()
            }
        }
        
        resortModes()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
}

extension LNProfilePhotoWall {
    private func resortModes() {
        columns.removeAll()
        var heightMap: [Int: CGFloat] = [:]
        for index in 0..<columnCount {
            columns.append([])
            heightMap[index] = 0.0
        }
        
        func minLine() -> Int {
            var index = 0
            heightMap.forEach {
                if $0.value < heightMap[index] ?? 0 {
                    index = $0.key
                }
            }
            return index
        }
        func maxLine() -> Int {
            var index = 0
            heightMap.forEach {
                if $0.value > heightMap[index] ?? 0 {
                    index = $0.key
                }
            }
            return index
        }
        
        allPhotos.forEach {
            let index = minLine()
            var height = heightMap[index] ?? 0.0
            height += $0.ratio
            heightMap[index] = height
            columns[index].append($0)
        }
        
        // 填充空白图片占位界面，用来保持所有列高度一致
        // 避免长的列表滑动的时候，短的列表会回弹
        let index = maxLine()
        let maxHeight = heightMap[index] ?? 0.0
        heightMap.forEach { key, value in
            if key == index { return }
            let offset = maxHeight - value
            let fillMode = LNProfilePhotoWallMode()
            fillMode.ratio = offset
            columns[key].append(fillMode)
        }
        
        tableViews.forEach { $0.reloadData() }
    }
}

extension LNProfilePhotoWall: UITableViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        tableViews.forEach {
            $0.contentOffset = scrollView.contentOffset
        }
    }
}

extension LNProfilePhotoWall: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let index = tableViews.firstIndex { $0 == tableView }
        
        guard let index, index < columns.count else { return 0 }
        
        return columns[index].count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: LNProfilePhotoWallCell.className, for: indexPath) as! LNProfilePhotoWallCell
        let index = tableViews.firstIndex { $0 == tableView }
        
        guard let index, index < columns.count else {
            return cell
        }
        
        let mode = columns[index][indexPath.row]
        cell.update(mode)
        cell.handler = { [weak self] mode in
            guard let self else { return }
            let urls = allPhotos.map { $0.url }
            let index = allPhotos.firstIndex(where: { $0.url == mode.url })
            presentImagePreview(urls, index ?? 0)
        }
        
        return cell
    }
}

extension LNProfilePhotoWall {
    private func setupViews() {
        addSubview(emptyView)
        emptyView.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            make.centerY.equalToSuperview().multipliedBy(0.6)
        }
        
        let stackView = UIStackView()
        stackView.axis = .horizontal
        stackView.spacing = 9
        stackView.distribution = .fillEqually
        addSubview(stackView)
        stackView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview().inset(16)
            make.bottom.equalToSuperview()
            make.top.equalToSuperview()
        }
        
        for _ in 0..<columnCount {
            let tableView = LNNestedTableView()
            tableView.separatorStyle = .none
            tableView.showsHorizontalScrollIndicator = false
            tableView.showsVerticalScrollIndicator = false
            tableView.register(LNProfilePhotoWallCell.self, forCellReuseIdentifier: LNProfilePhotoWallCell.className)
            tableView.dataSource = self
            tableView.tableDelegate = self
            tableView.allowsSelection = false
            tableView.contentInset = .init(top: 6, left: 0, bottom: 0, right: 0)
            tableView.backgroundColor = .clear
            tableView.publisher(for: \.contentSize).removeDuplicates().sink
            { [weak self] newValue in
                guard let self else { return }
                let maxHeightItem = tableViews.max(by: {
                    ($0.contentSize.height + $0.contentInset.top) >
                    ($1.contentSize.height + $1.contentInset.top)
                })
                contentHeight = (maxHeightItem?.contentInset.top ?? 0) + (maxHeightItem?.contentSize.height ?? 0)
            }.store(in: &cancellables)
            stackView.addArrangedSubview(tableView)
            tableViews.append(tableView)
        }
    }
}

private class LNProfilePhotoWallCell: UITableViewCell {
    private let photo = UIImageView()
    
    private var curMode: LNProfilePhotoWallMode?
    var handler: ((LNProfilePhotoWallMode) -> Void)?
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        photo.contentMode = .scaleAspectFill
        photo.layer.cornerRadius = 12
        photo.clipsToBounds = true
        contentView.addSubview(photo)
        photo.onTap { [weak self] in
            guard let self else { return }
            guard let curMode, !curMode.url.isEmpty else { return }
            handler?(curMode)
        }
    }
    
    func update(_ mode: LNProfilePhotoWallMode) {
        photo.snp.remakeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.top.equalToSuperview().offset(10)
            make.bottom.equalToSuperview()
            make.height.equalTo(photo.snp.width).multipliedBy(mode.ratio).priority(.high)
        }

        photo.sd_setImage(with: URL(string: mode.url))
        curMode = mode
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
}
