//
//  LNGameMateListView.swift
//  Lanu
//
//  Created by OneeChan on 2025/11/14.
//

import Foundation
import UIKit
import SnapKit
import Combine
import MJRefresh

class LNGameMateListView: UIView {
    private(set) var curMateList: [LNGameMateListItemVO] = []
    
    private var topCategory: String = ""
    private var category: String?
    private var filter = LNGameMateFilter()
    private var nextTag: String?
    private let pageSize = 30
    
    private let emptyView = LNNoMoreDataView()
    private let tableView = UITableView()
    private var loading = false
    
    private let bannerIndex = 1
    private var bannerList: [LNBannerInfoVO] = []
    private var bannerLoading = false
    private var bannerLoaded = false
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        setupViews()
    }
    
    func loadListIfNeed() {
        if !curMateList.isEmpty { return }
        
        tableView.mj_header?.beginRefreshing()
    }
    
    func reloadList(newTopCategory: String, newCategory: String?, filter: LNGameMateFilter) {
        topCategory = newTopCategory
        category = newCategory
        self.filter = filter
        bannerLoaded = false
        
        tableView.mj_header?.beginRefreshing()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension LNGameMateListView {
    private var shouldShowBannerCell: Bool {
        viewController is LNHomeViewController && curMateList.count > 1 && !bannerList.isEmpty
    }

    private func isBannerRow(_ row: Int) -> Bool {
        shouldShowBannerCell && row == bannerIndex
    }

    private func mateIndex(for row: Int) -> Int {
        if shouldShowBannerCell && row > bannerIndex {
            return row - 1
        }
        return row
    }

    private func loadList() {
        guard !loading else { return }
        loading = true
        let curNext = nextTag ?? ""
        LNGameMateManager.shared.getGameMateList(
            topCategory: topCategory, category: category,
            filter: filter, size: pageSize, next: curNext
        ) { [weak self] list, nextTag in
            guard let self else { return }
            loading = false
            if let list {
                if curNext.isEmpty {
                    curMateList.removeAll()
                }
                curMateList.append(contentsOf: list)
                self.nextTag = nextTag
                loadBannerIfNeed(force: curNext.isEmpty)
                tableView.reloadData()
                
                if curMateList.isEmpty {
                    emptyView.showNoData(tips: .init(key: "A00039"))
                } else {
                    emptyView.hide()
                }
            } else {
                if curMateList.isEmpty {
                    emptyView.showNetworkError()
                }
            }
            
            self.tableView.mj_header?.endRefreshing()
            if nextTag?.isEmpty != false {
                tableView.mj_footer?.endRefreshingWithNoMoreData()
            } else {
                tableView.mj_footer?.endRefreshing()
            }
        }
    }

    private func loadBannerIfNeed(force: Bool = false) {
        guard viewController is LNHomeViewController, curMateList.count > 1 else {
            if !bannerList.isEmpty {
                bannerList.removeAll()
                tableView.reloadData()
            }
            return
        }

        if bannerLoading {
            return
        }
        if bannerLoaded && !force {
            return
        }

        bannerLoading = true
        LNConfigManager.shared.getBannerList(adSlot: 1) { [weak self] list in
            guard let self else { return }
            bannerLoading = false
            bannerLoaded = true
            bannerList = list ?? []
            tableView.reloadData()
        }
    }
    
    func reportExposure() {
        let frame = convert(bounds, to: nil)
        guard frame.origin.x == 0,
              tableView.contentOffset.y >= 0 else {
            return
        }
        
        guard let indexs = tableView.indexPathsForVisibleRows,
              !indexs.isEmpty else {
            return
        }
        
        var items = Set<String>()
        for index in indexs {
            if isBannerRow(index.row) {
                continue
            }
            let mateIdx = mateIndex(for: index.row)
            guard mateIdx >= 0, mateIdx < curMateList.count else { continue }
            items.insert(curMateList[mateIdx].userNo)
        }

        if items.isEmpty {
            return
        }
        
        LNStatisticManager.shared.reportExposure(uids: Array(items)) { _ in }
    }
}

extension LNGameMateListView: LNGameFilterPanelDelegate {
    func onGameFilterPanel(panel: LNGameFilterPanel, didSelectFilter filter: LNGameMateFilter,
                           topType: LNGameTypeItemVO, category: LNGameCategoryItemVO) {
        if viewController is LNHomeViewController {
            pushToGameMateList(topCategory: topType, category: category, filter: filter)
        } else {
            reloadList(newTopCategory: topType.code, newCategory: category.code, filter: filter)
            viewController?.title = category.name
        }
    }
}

extension LNGameMateListView: LNGameMateListMenuViewDelegate {
    func menuView(view: LNGameMateListMenuView, scoreTypeChanged newType: LNSortedType) {
        filter.sortByStar = newType
        tableView.mj_header?.beginRefreshing()
    }
    
    func menuView(view: LNGameMateListMenuView, priceTypeChanged newType: LNSortedType) {
        filter.sortByPrice = newType
        tableView.mj_header?.beginRefreshing()
    }
    
    func menuViewDidClickFind(view: LNGameMateListMenuView) {
        let filterPanel = LNGameFilterPanel()
        filterPanel.delegate = self
        filterPanel.popup()
    }
}

extension LNGameMateListView: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        curMateList.count + (shouldShowBannerCell ? 1 : 0)
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if isBannerRow(indexPath.row) {
            let cell = tableView.dequeueReusableCell(withIdentifier: LNMateAdBannerCell.className, for: indexPath) as! LNMateAdBannerCell
            cell.update(items: bannerList)
            return cell
        }

        let cell = tableView.dequeueReusableCell(withIdentifier: LNGameMateListCell.className, for: indexPath) as! LNGameMateListCell

        let data = curMateList[mateIndex(for: indexPath.row)]
        cell.update(data)
        
        return cell
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if isBannerRow(indexPath.row) {
            return 70
        }
        return UITableView.automaticDimension
    }
    
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        reportExposure()
    }
    
    func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
        reportExposure()
    }
    
    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        if !decelerate {
            reportExposure()
        }
    }
}

extension LNGameMateListView {
    private func setupViews() {
        let menu = buildMenu()
        addSubview(menu)
        menu.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
            make.top.equalToSuperview()
        }
        
        let listView = buildListView()
        addSubview(listView)
        listView.snp.makeConstraints { make in
            make.leading.trailing.bottom.equalToSuperview()
            make.top.equalTo(menu.snp.bottom).offset(10)
        }
    }
    
    private func buildMenu() -> UIView {
        let menu = LNGameMateListMenuView()
        menu.delegate = self
        
        return menu
    }
    
    private func buildListView() -> UIView {
        let header = MJRefreshNormalHeader { [weak self] in
            guard let self else { return }
            self.nextTag = nil
            self.loadList()
        }
        header.lastUpdatedTimeLabel?.isHidden = true
        header.stateLabel?.isHidden = true
        header.endRefreshingCompletionBlock = { [weak self] in
            guard let self else { return }
            reportExposure()
        }
        tableView.mj_header = header
        
        let footer = MJRefreshAutoNormalFooter { [weak self] in
            guard let self else { return }
            self.loadList()
        }
        footer.setTitle("", for: .noMoreData)
        footer.setTitle(.init(key: "A00046"), for: .idle)
        footer.endRefreshingCompletionBlock = { [weak self] in
            guard let self else { return }
            reportExposure()
        }
        tableView.mj_footer = footer
        
        tableView.register(LNGameMateListCell.self, forCellReuseIdentifier: LNGameMateListCell.className)
        tableView.register(LNMateAdBannerCell.self, forCellReuseIdentifier: LNMateAdBannerCell.className)
        tableView.dataSource = self
        tableView.delegate = self
        tableView.allowsSelection = false
        tableView.separatorStyle = .none
        tableView.backgroundColor = .clear
        tableView.rowHeight = UITableView.automaticDimension
        
        tableView.addSubview(emptyView)
        emptyView.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            make.centerY.equalToSuperview().multipliedBy(0.6)
        }
        
        return tableView
    }
}

#if DEBUG

import SwiftUI

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

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