//
//  VideoSeatLayout.swift
//  TUIVideoSeat
//
//  Created by janejntang on 2023/3/16.
//

import Foundation

protocol VideoSeatLayoutDelegate: AnyObject {
    func updateNumberOfPages(numberOfPages: NSInteger)
}

class VideoSeatLayout: UICollectionViewFlowLayout {
    private var prePageCount: NSInteger = 1
    private let largeCellIndex = 0
    private let smallCellIndex = 1

    private var collectionViewHeight: CGFloat {
        return collectionView?.bounds.height ?? UIScreen.main.bounds.height
    }

    private var collectionViewWidth: CGFloat {
        return collectionView?.bounds.width ?? kScreenWidth
    }

    private var isPortrait: Bool {
        return collectionViewHeight > collectionViewWidth
    }

    private var kVideoSeatCellNumberOfOneRow: CGFloat {
        return isPortrait ? 2 : 3
    }

    private var kMaxShowCellCount: Int {
        return 6
    }

    private let itemDiffSpace: CGFloat = 5.0

    private var itemWidthHeight: CGFloat {
        let minimumDistance = min(collectionViewHeight, collectionViewWidth)
        let availableSpace = minimumDistance - (kVideoSeatCellNumberOfOneRow + 1) * itemDiffSpace
        if isPortrait {
            return availableSpace / kVideoSeatCellNumberOfOneRow
        } else {
            return availableSpace / (CGFloat(kMaxShowCellCount) / kVideoSeatCellNumberOfOneRow)
        }
    }

    private let viewModel: TUIVideoSeatViewModel
    
    fileprivate var layoutAttributeArray: [UICollectionViewLayoutAttributes] = []

    init(viewModel: TUIVideoSeatViewModel) {
        self.viewModel = viewModel
        super.init()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func prepare() {
        super.prepare()
        calculateEachCellFrame()
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        return layoutAttributeArray
    }

    override var collectionViewContentSize: CGSize {
        return CGSize(width: CGFloat(prePageCount) * collectionViewWidth, height: collectionViewHeight)
    }

    weak var delegate: VideoSeatLayoutDelegate?

    func getMiniscreenFrame(item: VideoSeatItem?) -> CGRect {
        var height = isPortrait ? 180.0 : 100.0
        var width = isPortrait ? 100.0 : 180.0
        if let item = item, !item.hasVideoStream {
            height = 100.0
            width = 100.0
        }
        return CGRect(x: collectionViewWidth - width - itemDiffSpace, y: itemDiffSpace, width: width, height: height)
    }
}

// MARK: - layout

extension VideoSeatLayout {
    private func calculateEachCellFrame() {
        guard let collectionViewWidth: CGFloat = collectionView?.bounds.width else { return }
        guard viewModel.listSeatItem.count > 0 else { return }
        layoutAttributeArray = []
        let section: Int = 0
        prePageCount = 1
        if viewModel.videoSeatViewType == .singleType {
            let indexPath = IndexPath(item: 0, section: 0)
            let cell = getFullScreenAttributes(indexPath: indexPath)
            layoutAttributeArray.append(cell)
        } else if viewModel.videoSeatViewType == .largeSmallWindowType {
            let largeIndexPath = IndexPath(item: largeCellIndex, section: section)
            let largeCell = getFullScreenAttributes(indexPath: largeIndexPath)
            largeCell.zIndex = largeCellIndex
            layoutAttributeArray.append(largeCell)
            let smallIndexPath = IndexPath(item: smallCellIndex, section: section)
            let smallCell = getSmallAttributes(indexPath: smallIndexPath)
            smallCell.zIndex = smallCellIndex
            layoutAttributeArray.append(smallCell)
        } else if viewModel.videoSeatViewType == .pureAudioType || viewModel.videoSeatViewType == .equallyDividedType {
            guard let itemCount = collectionView?.numberOfItems(inSection: section) else { return }
            let isMultipage = itemCount >= kMaxShowCellCount
            for i in 0 ... itemCount - 1 {
                let indexPath = IndexPath(item: i, section: section)
                var cell: UICollectionViewLayoutAttributes
                if isMultipage {
                    cell = getMultipageEquallyDividedAttributes(indexPath: indexPath, item: i, itemCount: itemCount, leftDiff: 0.0)
                } else {
                    cell = getEquallyDividedAttributes(indexPath: indexPath, item: i, itemCount: itemCount, leftDiff: 0.0)
                }
                layoutAttributeArray.append(cell)
            }
            prePageCount = Int(ceil(CGFloat(itemCount) / CGFloat(kMaxShowCellCount)))
        } else if viewModel.videoSeatViewType == .speechType {
            guard let itemCount = collectionView?.numberOfItems(inSection: section) else { return }
            let isMultipage = (itemCount - 1) >= kMaxShowCellCount
            for i in 0 ... itemCount {
                let indexPath = IndexPath(item: i, section: section)
                var cell: UICollectionViewLayoutAttributes
                if i == 0 {
                    cell = getFullScreenAttributes(indexPath: indexPath)
                } else if isMultipage {
                    cell = getMultipageEquallyDividedAttributes(indexPath: indexPath, item: i - 1,
                                                                itemCount: itemCount - 1,
                                                                leftDiff: collectionViewWidth)
                } else {
                    cell = getEquallyDividedAttributes(indexPath: indexPath, item: i - 1,
                                                       itemCount: itemCount - 1,
                                                       leftDiff: collectionViewWidth)
                }
                layoutAttributeArray.append(cell)
            }
            prePageCount = Int(ceil(CGFloat(itemCount - 1) / CGFloat(kMaxShowCellCount))) + 1
        }
        delegate?.updateNumberOfPages(numberOfPages: prePageCount)
    }

    // Full screen cell layout information
    private func getFullScreenAttributes(indexPath: IndexPath) ->
        UICollectionViewLayoutAttributes {
        let cell = UICollectionViewLayoutAttributes(forCellWith: indexPath)
        cell.frame = CGRect(x: 0, y: 0, width: collectionViewWidth, height: collectionViewHeight)
        return cell
    }

    private func getSmallAttributes(indexPath: IndexPath) -> UICollectionViewLayoutAttributes {
        let cell = UICollectionViewLayoutAttributes(forCellWith: indexPath)
        cell.frame = getMiniscreenFrame(item: nil)
        return cell
    }

    private func getEquallyDividedAttributes(indexPath: IndexPath, item: Int, itemCount: Int, leftDiff: CGFloat) ->
        UICollectionViewLayoutAttributes {
        /*-----------------item&page&currentPageItemCount&cell-----------------**/
        let item = item + 1
        let page = Int(ceil(CGFloat(item) / CGFloat(kMaxShowCellCount)))
        let currentPageItemCount = min(itemCount, page * kMaxShowCellCount) - (page - 1) * kMaxShowCellCount // Number of items on the current page
        let cell = UICollectionViewLayoutAttributes(forCellWith: indexPath)

        /*-----------------currentPageAllRow&beginCellY&beginCellLeft-----------------**/
        let currentPageAllRow = Int(ceil(CGFloat(currentPageItemCount) / CGFloat(kVideoSeatCellNumberOfOneRow))) // Calculate the total number of rows on this page
        let itemAllHeight = (itemWidthHeight + itemDiffSpace) * CGFloat(currentPageAllRow) - itemDiffSpace
        let itemAllWidth = (itemWidthHeight + itemDiffSpace) * kVideoSeatCellNumberOfOneRow - itemDiffSpace
        let beginCellY = (collectionViewHeight - itemAllHeight) * 0.5 // Calculate beginCellTop
        let beginCellX = (collectionViewWidth - itemAllWidth) * 0.5 // Calculate beginCellTop
        let beginCellLeft = CGFloat(page - 1) * collectionViewWidth // Calculate beginCellLeft

        /*-----------------itemIndex&column&row-----------------**/
        let itemIndex = item - (page - 1) * kMaxShowCellCount // What is the number on this page?
        let column = (itemIndex - 1) % Int(kVideoSeatCellNumberOfOneRow) // Which column of cell is on the current page starting from 0?
        let row = Int(ceil(CGFloat(itemIndex) / CGFloat(kVideoSeatCellNumberOfOneRow))) // What is the row of cell on the current page?
        let itemY = beginCellY + (itemWidthHeight + itemDiffSpace) * CGFloat(row - 1)
        var itemX = 0.0
        if currentPageAllRow == row {
            // Adjust the center of the last row
            let lastRowItemCount = currentPageItemCount - (row - 1) * Int(kVideoSeatCellNumberOfOneRow)
            let lastRowBeginCellLeft = (collectionViewWidth - (itemWidthHeight + itemDiffSpace) * CGFloat(lastRowItemCount) - itemDiffSpace) * 0.5
            itemX = lastRowBeginCellLeft + beginCellLeft + (itemWidthHeight + itemDiffSpace) * CGFloat(column)
        } else {
            itemX = beginCellX + beginCellLeft + (itemWidthHeight + itemDiffSpace) * CGFloat(column)
        }
        cell.frame = CGRect(x: leftDiff + itemX, y: itemY, width: itemWidthHeight, height: itemWidthHeight)
        return cell
    }

    private func getMultipageEquallyDividedAttributes(indexPath: IndexPath, item: Int, itemCount: Int, leftDiff: CGFloat) ->
        UICollectionViewLayoutAttributes {
        let item = item + 1
        let page = Int(ceil(CGFloat(item) / CGFloat(kMaxShowCellCount)))
        let cell = UICollectionViewLayoutAttributes(forCellWith: indexPath)
        let currentPageAllRow = kMaxShowCellCount / Int(kVideoSeatCellNumberOfOneRow)
        let itemAllHeight = (itemWidthHeight + itemDiffSpace) * CGFloat(currentPageAllRow) - itemDiffSpace
        let itemAllWidth = (itemWidthHeight + itemDiffSpace) * kVideoSeatCellNumberOfOneRow - itemDiffSpace
        let beginCellY = (collectionViewHeight - itemAllHeight) * 0.5
        let beginCellX = (collectionViewWidth - itemAllWidth) * 0.5
        let beginCellLeft = CGFloat(page - 1) * collectionViewWidth
        let itemIndex = item - (page - 1) * kMaxShowCellCount
        let column = (itemIndex - 1) % Int(kVideoSeatCellNumberOfOneRow)
        let row = Int(ceil(CGFloat(itemIndex) / CGFloat(kVideoSeatCellNumberOfOneRow)))
        let itemY = beginCellY + (itemWidthHeight + itemDiffSpace) * CGFloat(row - 1)
        let itemX = beginCellX + beginCellLeft + (itemWidthHeight + itemDiffSpace) * CGFloat(column)
        cell.frame = CGRect(x: leftDiff + itemX, y: itemY, width: itemWidthHeight, height: itemWidthHeight)
        return cell
    }
}
