//
//  LNAutoFillStackView.swift
//  Lanu
//
//  Created by OneeChan on 2025/12/12.
//

import Foundation
import UIKit
import SnapKit


class LNAutoFillStackView: UIStackView {
    var itemSpacing: CGFloat = 0 {
        didSet {
            if oldValue != itemSpacing {
                sortItemViews()
            }
        }
    }
    
    private var lineViews: [UIStackView] = []
    private(set) var curItemViews: [UIView] = []
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        axis = .vertical
        alignment = .leading
    }
    
    func update(_ itemViews: [UIView]) {
        arrangedSubviews.forEach {
            removeArrangedSubview($0)
            $0.removeFromSuperview()
        }
        lineViews.removeAll()
        curItemViews.removeAll()
        
        itemViews.forEach {
            $0.layoutIfNeeded()
            curItemViews.append($0)
        }
        
        sortItemViews()
    }
    
    func append(_ itemViews: [UIView]) {
        itemViews.forEach {
            $0.layoutIfNeeded()
            curItemViews.append($0)
        }
        sortItemViews()
    }
    
    func remove(_ itemViews: [UIView]) {
        curItemViews.removeAll {
            itemViews.contains($0)
        }
        sortItemViews()
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        sortItemViews()
    }
    
    required init(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension LNAutoFillStackView {
    private func sortItemViews() {
        let maxWidth = bounds.width
        
        var lines: [[UIView]] = []
        var curLine: [UIView] = []
        var totalWidth = 0.0
        curItemViews.forEach {
            if curLine.isEmpty {
                curLine.append($0)
                totalWidth = $0.frame.width
            } else {
                if totalWidth + $0.bounds.width + itemSpacing > maxWidth {
                    lines.append(curLine)
                    
                    curLine = []
                    totalWidth = 0.0
                }
                if curLine.isEmpty {
                    totalWidth = $0.bounds.width
                } else {
                    totalWidth += $0.bounds.width + itemSpacing
                }
                curLine.append($0)
            }
        }
        lines.append(curLine)
        
        if lineViews.count != lines.count {
            lineViews.forEach {
                removeArrangedSubview($0)
                $0.removeFromSuperview()
            }
            lineViews.removeAll()
            for _ in 0..<lines.count {
                let lineView = buildLine()
                lineViews.append(lineView)
                addArrangedSubview(lineView)
            }
        }
        lineViews.forEach { line in
            line.arrangedSubviews.forEach {
                line.removeArrangedSubview($0)
                $0.removeFromSuperview()
            }
        }
        for (index, lineView) in lineViews.enumerated() {
            let views = lines[index]
            views.forEach {
                lineView.addArrangedSubview($0)
            }
        }
    }
    
    private func buildLine() -> UIStackView {
        let stackView = UIStackView()
        stackView.axis = .horizontal
        stackView.spacing = itemSpacing
        
        return stackView
    }
}

#if DEBUG

import SwiftUI

struct LNMultiAutoLineStackViewPreview: UIViewRepresentable {
    func makeUIView(context: Context) -> some UIView {
        let container = UIView()
        container.backgroundColor = .lightGray
        
        let view = LNAutoFillStackView()
        view.backgroundColor = .orange
        container.addSubview(view)
        view.snp.makeConstraints { make in
            make.leading.trailing.equalToSuperview()
            make.centerY.equalToSuperview()
        }
        
        return container
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) { }
}

#Preview(body: {
    LNMultiAutoLineStackViewPreview()
})
#endif

