import UIKit
import Kingfisher

class ImageCell: UICollectionViewCell {
    private var imgView: UIImageView!

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.imgView = UIImageView()
        self.contentView.addSubview(self.imgView)
        self.imgView.translatesAutoresizingMaskIntoConstraints = false
        self.imgView.contentMode = .scaleAspectFill
        self.imgView.layer.masksToBounds = true
        NSLayoutConstraint.activate([
            self.imgView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor),
            self.imgView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor),
            self.imgView.topAnchor.constraint(equalTo: self.contentView.topAnchor),
            self.imgView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor)
        ])
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        self.imgView.kf.cancelDownloadTask()
    }

    func configure(with image: String) {
        guard let url = URL(string: image) else { return }
        self.imgView.kf.setImage(with: url, options: [
            .processor(DownsamplingImageProcessor(size: self.frame.size)),
            .scaleFactor(UIScreen.main.scale),
            .cacheOriginalImage
        ])
    }
}

class ImageGrid: UICollectionView, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
    private var images: [String] = []
    private var columnsCount: Int = 1
    private var spacing: CGFloat = 0
    
    var selectionChanged: ((Int) -> Void)?
    var preferredMaxLayoutWidth: CGFloat = 0

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
        super.init(frame: frame, collectionViewLayout: layout)

        self.register(ImageCell.self, forCellWithReuseIdentifier: "ImageCell")
        self.dataSource = self
        self.delegate = self
    }

    convenience init(columns: Int, spacing: CGFloat = 0) {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .vertical
        layout.minimumInteritemSpacing = spacing
        layout.minimumLineSpacing = spacing
        layout.estimatedItemSize = .zero
        self.init(frame: .zero, collectionViewLayout: layout)
        self.backgroundColor = .clear
        self.columnsCount = columns
        self.spacing = spacing
    }

    override var intrinsicContentSize: CGSize {
        let size = self.collectionViewLayout.collectionViewContentSize
        if size == .zero && self.preferredMaxLayoutWidth != 0 {
            let cellSize: CGFloat = (self.preferredMaxLayoutWidth - self.spacing*(CGFloat(self.columnsCount) - 1))/CGFloat(self.columnsCount)
            let rows: Int = self.images.count/self.columnsCount + (self.images.count % self.columnsCount == 0 ? 0 : 1)
            let height = cellSize*CGFloat(rows) + CGFloat(rows - 1)*self.spacing
            print("intrinsicContentSize: \(CGSize(width: self.preferredMaxLayoutWidth, height: height))")
            return CGSize(width: self.preferredMaxLayoutWidth, height: height)
        }

        print("intrinsicContentSize: \(size)")
        return size
    }

    func set(images: [String]) {
        self.images = images
        self.reloadData()
        self.invalidateIntrinsicContentSize()
    }

    func set(columnsCount: Int) {
        self.columnsCount = columnsCount
        self.reloadData()
        self.invalidateIntrinsicContentSize()
    }

    // MARK: - UICollectionViewDataSource

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.images.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = self.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath) as? ImageCell else { return UICollectionViewCell() }
        cell.configure(with: self.images[indexPath.row])
        return cell
    }

    // MARK: - UICollectionViewDelegateFlowLayout

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let cellSize = (self.bounds.size.width - self.spacing*(CGFloat(self.columnsCount) - 1))/CGFloat(self.columnsCount)
        return CGSize(width: cellSize, height: cellSize)
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        collectionView.deselectItem(at: indexPath, animated: false)
        self.selectionChanged?(indexPath.row)
    }
}
