//
//  LNGameMateListCell.swift
//  Lanu
//
//  Created by OneeChan on 2025/11/16.
//

import Foundation
import UIKit
import SnapKit
import Combine


class LNGameMateListCell: UITableViewCell {
    private let avatar = UIImageView()
    private let onlineView = LNOnlineView()
    
    private let playButton = UIButton()
    private let voiceLabel = UILabel()
    private let voiceWaveView = LNVoiceWaveView()
    
    private let priceLabel = UILabel()
    private let unitLabel = UILabel()
    
    private let saleView = UIView()
    private let discountView = LNNewbieDiscountView()
    
    private let nameLabel = UILabel()
    private let genderView = LNGenderView()
    
    private let newbieView = UIView()
    
    private let scoreView = UIView()
    private let scoreLabel = UILabel()
    private let orderCountLabel = UILabel()
    
    private let gameIc = UIImageView()
    private let gameNameLanel = UILabel()
    
    private let bioLabel = UILabel()
    
    private let maxShow = 3
    private let photoView = UIStackView()
    private var photos: [UIImageView] = []
    
    private var curItem: LNGameMateListItemVO?
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        setupViews()
        
        LNEventDeliver.addObserver(self)
    }
    
    func update(_ item: LNGameMateListItemVO) {
        avatar.showAvatar(item.avatar)
        onlineView.isHidden = !item.online
        priceLabel.text = item.price.toDisplay
        unitLabel.text = "/\(item.unit)"
        
        nameLabel.text = item.nickname
        genderView.update(item.gender, item.age)
        
        scoreLabel.text = "\(item.star)"
        orderCountLabel.text = .init(key: "A00037", item.orderCount)
        
        gameIc.sd_setImage(with: URL(string: item.categoryIcon))
        gameNameLanel.text = item.categoryName
        
        bioLabel.text = item.summary
        bioLabel.superview?.isHidden = item.summary.isEmpty
        
        newbieView.isHidden = !item.newcomer
        
        if item.images.isEmpty {
            photoView.isHidden = true
            bioLabel.numberOfLines = 4
        } else {
            for index in 0..<maxShow {
                if index < item.images.count {
                    photos[index].sd_setImage(with: URL(string: item.images[index]))
                } else {
                    photos[index].sd_setImage(with: nil)
                }
            }
            photoView.isHidden = false
            bioLabel.numberOfLines = 1
        }
        
        if let curItem {
            LNVoiceResourceManager.shared.cancelLoadingAsset(urlStr: curItem.voiceBar)
        }
        
        curItem = item
        
        if LNVoicePlayer.shared.playingUrl == curItem?.voiceBar {
            voiceWaveView.startAnimate()
        } else {
            voiceWaveView.stopAnimate()
        }
        
        playButton.isHidden = true
        if !item.voiceBar.isEmpty {
            LNVoiceResourceManager.shared.getRemoteAudioDuration(urlStr: item.voiceBar)
            { [weak self] duration, error in
                guard let self else { return }
                guard let duration, error == nil else { return }
                guard curItem?.id == item.id else { return }
                voiceLabel.text = duration.durationDisplay
                playButton.isHidden = false
            }
        }
        
        updateDiscount()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension LNGameMateListCell: LNVoicePlayerNotify {
    func onAudioStartPlay(path: String) {
        guard path == curItem?.voiceBar else { return }
        voiceWaveView.startAnimate()
    }
    
    func onAudioStopPlay(path: String) {
        guard path == curItem?.voiceBar else { return }
        voiceWaveView.stopAnimate()
        let url = curItem?.voiceBar
        LNVoiceResourceManager.shared.getRemoteAudioDuration(urlStr: curItem?.voiceBar)
        { [weak self] duration, err in
            guard let self else { return }
            guard let duration, err == nil else { return }
            guard curItem?.voiceBar == url else { return }
            voiceLabel.text = duration.durationDisplay
        }
    }
    
    func onAudioUpdateDuration(path: String, cur: TimeInterval, total: TimeInterval) {
        guard path == curItem?.voiceBar else { return }
        voiceLabel.text = (total - cur).durationDisplay
    }
}

extension LNGameMateListCell: LNOrderManagerNotify {
    func onMyDiscountInfoChanged(info: LNOrderDiscountVO?) {
        updateDiscount()
    }
    
    private func updateDiscount() {
        guard let curItem else { return }
        if curItem.userNo.isMyUid == false,
           let discount = LNOrderManager.shared.discountFor(curItem.price) {
            saleView.isHidden = false
            discountView.update(1 - discount)
            priceLabel.textColor = .init(hex: "#FF6F32")
            priceLabel.text = (curItem.price * discount).toDisplay
        } else {
            saleView.isHidden = true
            priceLabel.textColor = .text_5
            priceLabel.text = curItem.price.toDisplay
        }
    }
}

extension LNGameMateListCell {
    private func setupViews() {
        backgroundColor = .clear
        
        let container = UIView()
        container.onTap { [weak self] in
            guard let self else { return }
            guard let curItem else { return }
            pushToSkillDetail(curItem.id)
        }
        contentView.addSubview(container)
        container.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(16)
            make.trailing.equalToSuperview().offset(-16)
            make.top.equalToSuperview()
            make.bottom.equalToSuperview().offset(-10).priority(.medium)
        }
        
        let bg = UIImageView()
        bg.image = .icGameMateListCellBg.resizableImage(
            withCapInsets: .init(top: 48, left: 53, bottom: 12, right: 17), resizingMode: .stretch
        )
        container.addSubview(bg)
        bg.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        
        let avatar = buildAvatar()
        container.addSubview(avatar)
        avatar.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(13)
            make.top.equalToSuperview().offset(12)
            make.bottom.lessThanOrEqualToSuperview().offset(-12)
        }
        
        let stackView = UIStackView()
        stackView.axis = .vertical
        stackView.spacing = 6
        container.addSubview(stackView)
        stackView.snp.makeConstraints { make in
            make.leading.equalTo(avatar.snp.trailing).offset(14)
            make.trailing.equalToSuperview().offset(-12)
            make.top.equalToSuperview().offset(10)
            make.bottom.lessThanOrEqualToSuperview().offset(-10)
        }
        
        stackView.addArrangedSubview(buildTextViews())
        stackView.addArrangedSubview(buildPhotos())
    }
    
    private func buildAvatar() -> UIView {
        let container = UIView()
        
        avatar.layer.cornerRadius = 38
        avatar.clipsToBounds = true
        avatar.contentMode = .scaleAspectFill
        container.addSubview(avatar)
        avatar.snp.makeConstraints { make in
            make.width.height.equalTo(76)
            make.top.equalToSuperview()
            make.horizontalEdges.equalToSuperview()
        }
        
        onlineView.offset = 5
        container.addSubview(onlineView)
        onlineView.snp.makeConstraints { make in
            make.edges.equalTo(avatar).inset(-2)
        }
        
        playButton.setBackgroundImage(.primary_7, for: .normal)
        playButton.layer.cornerRadius = 11
        playButton.clipsToBounds = true
        playButton.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            guard let curItem, !curItem.voiceBar.isEmpty else { return }
            if LNVoicePlayer.shared.playingUrl == curItem.voiceBar {
                LNVoicePlayer.shared.stop()
            } else {
                LNVoicePlayer.shared.play(curItem.voiceBar)
            }
        }), for: .touchUpInside)
        container.addSubview(playButton)
        playButton.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            make.bottom.equalTo(avatar).offset(10)
            make.width.equalTo(64)
            make.height.equalTo(22)
        }
        
        let voice = UIView()
        voice.isUserInteractionEnabled = false
        playButton.addSubview(voice)
        voice.snp.makeConstraints { make in
            make.center.equalToSuperview()
        }
        
        voiceWaveView.build()
        voice.addSubview(voiceWaveView)
        voiceWaveView.snp.makeConstraints { make in
            make.leading.centerY.equalToSuperview()
            make.width.equalTo(19)
            make.height.equalTo(11)
        }
        
        voiceLabel.font = .heading_h5
        voiceLabel.textColor = .text_1
        voice.addSubview(voiceLabel)
        voiceLabel.snp.makeConstraints { make in
            make.verticalEdges.equalToSuperview()
            make.trailing.equalToSuperview()
            make.leading.equalTo(voiceWaveView.snp.trailing).offset(4)
        }
        
        let price = UIView()
        container.addSubview(price)
        price.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            make.top.equalTo(playButton.snp.bottom).offset(2)
        }
        
        let coin = UIImageView.coinImageView()
        price.addSubview(coin)
        coin.snp.makeConstraints { make in
            make.leading.centerY.equalToSuperview()
            make.width.height.equalTo(18)
        }
        
        priceLabel.font = .heading_h4
        priceLabel.textColor = .text_5
        priceLabel.setContentHuggingPriority(.required, for: .vertical)
        priceLabel.setContentCompressionResistancePriority(.required, for: .vertical)
        price.addSubview(priceLabel)
        priceLabel.snp.makeConstraints { make in
            make.verticalEdges.equalToSuperview()
            make.leading.equalTo(coin.snp.trailing)
        }
        
        unitLabel.font = .body_s
        unitLabel.textColor = .text_3
        price.addSubview(unitLabel)
        unitLabel.snp.makeConstraints { make in
            make.centerY.trailing.equalToSuperview()
            make.leading.equalTo(priceLabel.snp.trailing).offset(1)
        }
        
        let saleView = buildSaleView()
        container.addSubview(saleView)
        saleView.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            make.top.equalTo(price.snp.bottom)
            make.bottom.equalToSuperview()
        }
        
        return container
    }
    
    private func buildBaseInfo() -> UIView {
        let container = UIView()
        container.isUserInteractionEnabled = false
        
        nameLabel.font = .heading_h4
        nameLabel.textColor = .text_5
        nameLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        container.addSubview(nameLabel)
        nameLabel.snp.makeConstraints { make in
            make.leading.equalToSuperview()
            make.top.equalToSuperview()
        }
        
        container.addSubview(genderView)
        genderView.snp.makeConstraints { make in
            make.leading.equalTo(nameLabel.snp.trailing).offset(4)
            make.centerY.equalTo(nameLabel)
            make.trailing.lessThanOrEqualToSuperview()
        }
        
        container.addSubview(scoreView)
        scoreView.snp.makeConstraints { make in
            make.leading.bottom.equalToSuperview()
            make.top.equalTo(nameLabel.snp.bottom).offset(3)
            make.height.equalTo(15)
        }
        
        let starIc = UIImageView()
        starIc.image = .icStarFill
        scoreView.addSubview(starIc)
        starIc.snp.makeConstraints { make in
            make.leading.equalToSuperview()
            make.width.height.equalTo(14)
            make.centerY.equalToSuperview()
        }
        
        scoreLabel.font = .heading_h5
        scoreLabel.textColor = .text_5
        scoreView.addSubview(scoreLabel)
        scoreLabel.snp.makeConstraints { make in
            make.leading.equalTo(starIc.snp.trailing).offset(3)
            make.centerY.equalToSuperview()
        }
        
        orderCountLabel.font = .body_xs
        orderCountLabel.textColor = .text_3
        scoreView.addSubview(orderCountLabel)
        orderCountLabel.snp.makeConstraints { make in
            make.leading.equalTo(scoreLabel.snp.trailing).offset(3)
            make.centerY.equalToSuperview()
            make.trailing.equalToSuperview()
        }
        
        return container
    }
    
    private func buildNewbieView() -> UIView {
        newbieView.layer.cornerRadius = 7.5
        newbieView.clipsToBounds = true
        newbieView.snp.makeConstraints { make in
            make.height.equalTo(15)
        }
        
        let holder = UIView()
        newbieView.addSubview(holder)
        holder.snp.makeConstraints { make in
            make.leading.equalToSuperview()
            make.verticalEdges.equalToSuperview()
        }
        
        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [
            UIColor(hex: "#FFD35B").cgColor,
            UIColor(hex: "#FFFFD35B").cgColor
        ]
        gradientLayer.startPoint = .init(x: 0, y: 0)
        gradientLayer.endPoint = .init(x: 1, y: 0)
        holder.layer.addSublayer(gradientLayer)
        holder.publisher(for: \.bounds).removeDuplicates().sink
        { [weak gradientLayer] newValue in
            guard let gradientLayer else { return }
            gradientLayer.frame = newValue
        }.store(in: &cancellables)
        
        let label = UILabel()
        label.font = .body_xs
        label.textColor = .init(hex: "#DE9D2E")
        label.text = .init(key: "A00310")
        holder.addSubview(label)
        label.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(6)
            make.trailing.equalToSuperview().offset(-14)
            make.centerY.equalToSuperview()
        }
        
        return newbieView
    }
    
    private func buildGameView() -> UIView {
        let container = UIView()
        container.isUserInteractionEnabled = false
        
        let background = UIView()
        background.backgroundColor = .fill_1
        background.layer.cornerRadius = 10
        container.addSubview(background)
        background.snp.makeConstraints { make in
            make.verticalEdges.equalToSuperview()
            make.leading.equalToSuperview()
        }
        
        let border = UIImageView()
        border.image = .primary_7
        border.layer.cornerRadius = 8
        border.clipsToBounds = true
        background.addSubview(border)
        border.snp.makeConstraints { make in
            make.verticalEdges.equalToSuperview().inset(2)
            make.leading.equalToSuperview().offset(2)
            make.width.height.equalTo(16)
        }
        
        gameIc.backgroundColor = .white
        gameIc.layer.cornerRadius = 7
        background.addSubview(gameIc)
        gameIc.snp.makeConstraints { make in
            make.center.equalTo(border)
            make.width.height.equalTo(14)
        }
        
        gameNameLanel.font = .body_xs
        gameNameLanel.textColor = .text_4
        gameNameLanel.setContentHuggingPriority(.required, for: .horizontal)
        gameNameLanel.setContentCompressionResistancePriority(.required, for: .horizontal)
        background.addSubview(gameNameLanel)
        gameNameLanel.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.trailing.equalToSuperview().offset(-6)
            make.leading.equalTo(border.snp.trailing).offset(2)
        }
        
        return container
    }
    
    private func buildBio() -> UIView {
        let container = UIView()
        container.isUserInteractionEnabled = false
        
        let bg = UIImageView()
        bg.image = .icGameMateListCellBubble.resizableImage(
            withCapInsets: .init(top: 16, left: 20, bottom: 12, right: 15), resizingMode: .stretch
        )
        container.addSubview(bg)
        bg.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.height.greaterThanOrEqualTo(29)
        }
        
        bioLabel.font = .body_xs
        bioLabel.textColor = .text_6
        container.addSubview(bioLabel)
        bioLabel.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview().inset(8)
            make.top.equalToSuperview().offset(9)
            make.bottom.equalToSuperview().offset(-6)
        }
        
        return container
    }
    
    private func buildTextViews() -> UIView {
        let stackView = UIStackView()
        stackView.axis = .vertical
        stackView.spacing = 2
        
        stackView.addArrangedSubview(buildBaseInfo())
        stackView.addArrangedSubview(buildNewbieView())
        stackView.addArrangedSubview(buildGameView())
        stackView.addArrangedSubview(buildBio())
        
        return stackView
    }
    
    private func buildPhotos() -> UIView {
        photoView.axis = .horizontal
        photoView.spacing = 6
        photoView.distribution = .fillEqually
        photoView.alignment = .leading
        
        for _ in 0..<maxShow {
            let icon = UIImageView()
            icon.layer.cornerRadius = 12
            icon.clipsToBounds = true
            icon.contentMode = .scaleAspectFill
            photoView.addArrangedSubview(icon)
            icon.snp.makeConstraints { make in
                make.height.equalTo(icon.snp.width)
            }
            photos.append(icon)
        }
        
        return photoView
    }
    
    private func buildSaleView() -> UIView {
        let triangle = UIImageView()
        triangle.image = .icTriangleDown.withRenderingMode(.alwaysTemplate)
        triangle.tintColor = .init(hex: "#FF6F32")
        triangle.transform = .init(scaleX: 1, y: -1)
        saleView.addSubview(triangle)
        triangle.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            make.top.equalToSuperview()
            make.width.equalTo(10)
            make.height.equalTo(4)
        }
        
        discountView.discountOnly = true
        saleView.addSubview(discountView)
        discountView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.bottom.equalToSuperview()
            make.top.equalTo(triangle.snp.bottom)
        }
        
        return saleView
    }
}


#if DEBUG

import SwiftUI

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

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

