//
//  LNProfileViewController.swift
//  Lanu
//
//  Created by OneeChan on 2025/11/26.
//

import Foundation
import UIKit
import SnapKit
import Combine


extension UIView {
    func pushToProfile(uid: String, scene: LNCommonSceneType = .unknown) {
        let vc = LNProfileViewController(uid: uid, scene: scene)
        navigationController?.pushViewController(vc, animated: true)
    }
}


class LNProfileViewController: LNViewController {
    private let scene: LNCommonSceneType
    private let uid: String
    
    private let avatar = UIImageView()
    private let titleLabel = UILabel()
    
    private let shareButton = UIButton()
    private let moreButton = UIButton()
    
    private let editButton = UIButton()
    private let editIc = UIImageView()
    private let editLabel = UILabel()
    
    private var hasFollow = false
    
    private let scrollView = LNNestedScrollView()
    private let cover = UIImageView()
    private let voiceBar = LNProfileVoiceBarView()    
    private let inRoomView = LNProfileInRoomView()
    private let userInfoView = LNProfileUserInfoView()
    private let infoView = LNProfileInfosView()
    private let bottomMenu = LNProfileBottomMenu()
    private let scoreView = LNProfileScoreFloatingView()
    
    private var detail: LNUserProfileVO?
    private var stayTimer: String?
    
    init(uid: String, scene: LNCommonSceneType) {
        self.scene = scene
        self.uid = uid
        
        super.init(nibName: nil, bundle: nil)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupViews()
        
        LNStatisticManager.shared.reportVisitor(uid: uid) { _ in }
        LNStatisticManager.shared.reportViewProfile(uid: uid)
        LNProfileManager.shared.getUserProfileDetail(uid: uid) { [weak self] info in
            guard let self else { return }
            guard let info else { return }
            
            self.detail = info
            updateContent()
        }
        LNEventDeliver.addObserver(self)
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        infoView.maxHeight = scrollView.bounds.height
        - fakeNaviBgView.bounds.height
        - scrollView.contentInset.bottom
        
        infoView.minHeight = scrollView.bounds.height
        - cover.bounds.height + 52 - scrollView.contentInset.bottom
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        LNDelayTask.cancel(key: stayTimer)
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        triggerAutoReplay()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension LNProfileViewController: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let offset = CGRectGetMinY(infoView.frame) - fakeNaviBgView.bounds.height
        let min = offset - UIView.statusBarHeight
        
        let progress: Double = if scrollView.contentOffset.y < min {
            0.0
        } else {
            (scrollView.contentOffset.y - min) / UIView.statusBarHeight
        }
        updateProgress(progress)
        infoView.progress = progress
    }
}

extension LNProfileViewController: LNProfileManagerNotify, LNRelationManagerNotify {
    func onUserInfoChanged(userInfo: LNUserProfileVO) {
        guard userInfo.userNo == uid else { return }
        detail = userInfo
        updateContent()
    }
    
    func onUserRelationChanged(uid: String, relation: LNUserRelationShip) {
        guard uid == detail?.userNo else { return }
        hasFollow = relation.contains(.followed)
    }
}

private extension LNProfileViewController {
    func triggerAutoReplay() {
        if !uid.isMyUid {
            stayTimer = LNDelayTask.perform(delay: 3) { [weak self] in
                guard let self else { return }
                LNGameMateManager.shared.triggerAutoReplayIfNeed(uid: uid)
            }
        }
    }
}

private extension LNProfileViewController {
    func updateContent() {
        guard let detail else { return }
        hasFollow = detail.follow
        
        avatar.showAvatar(detail.avatar)
        titleLabel.text = detail.nickname
        shareButton.isHidden = !detail.playmate || !detail.userNo.isMyUid
        editButton.isHidden = !detail.userNo.isMyUid
        moreButton.isHidden = detail.userNo.isMyUid
        
        cover.showAvatar(detail.avatar)
        userInfoView.update(detail)
        inRoomView.update(detail.userNo)
        voiceBar.update(detail.voiceBar)
        infoView.update(detail)
        bottomMenu.update(detail, scene: scene)
        scoreView.update(detail)
    }
    
    func updateProgress(_ progress: Double) {
        navigationBarColor = .white.withAlphaComponent(progress)
        
        avatar.alpha = progress
        titleLabel.alpha = progress
        
        let tintColor = UIColor.white.interpolateHSB(to: .text_4, progress: progress)
        backButton.tintColor = tintColor
        shareButton.tintColor = tintColor
        editIc.tintColor = tintColor
        editLabel.textColor = tintColor
        moreButton.tintColor = tintColor
        
        let background = UIColor.black.withAlphaComponent(0.4 * (1 - progress))
        shareButton.backgroundColor = background
        editButton.backgroundColor = background
        moreButton.backgroundColor = background
        
        editLabel.isHidden = progress > 0.35
    }
    
    func showMoreMenu() {
        let panel = LNBottomSheetMenu()
        var menu: [String] = [
            .init(key: "A00043"),
            detail?.userNo.isInMyBlackList != true ? .init(key: "A00044") : .init(key: "A00045")
        ]
        if hasFollow {
            menu.insert(.init(key: "A00026"), at: 0)
        }
        panel.update(menu) { [weak self] index, _ in
            guard let self else { return }
            guard let detail else { return }
            if hasFollow {
                if index == 0 {
                    LNCommonAlertView.showUnfollowAlert(uid: detail.userNo)
                } else if index == 1 {
                    view.pushToReport(uid: detail.userNo)
                } else if index == 2 {
                    if detail.userNo.isInMyBlackList {
                        LNRelationManager.shared.blackListUser(uid: detail.userNo, black: false, handler: nil)
                    } else {
                        LNCommonAlertView.showBlackAlert(uid: detail.userNo)
                    }
                }
            } else {
                if index == 0 {
                    view.pushToReport(uid: detail.userNo)
                } else if index == 1 {
                    if detail.userNo.isInMyBlackList {
                        LNRelationManager.shared.blackListUser(uid: detail.userNo, black: false, handler: nil)
                    } else {
                        LNCommonAlertView.showBlackAlert(uid: detail.userNo)
                    }
                }
            }
        }
        panel.popup()
    }
    
    func setupViews() {
        setupNavBar()
        
        scrollView.contentInsetAdjustmentBehavior = .never
        scrollView.showsVerticalScrollIndicator = false
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.backgroundColor = .fill
        scrollView.scrollDelegate = self
        scrollView.contentInset = .init(top: 0, left: 0, bottom: uid.isMyUid ? 0 : 80, right: 0)
        scrollView.clipsToBounds = false
        scrollView.bounces = false
        view.addSubview(scrollView)
        scrollView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.top.equalTo(fakeNaviBgView)
            make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom)
        }
        
        let fakeView = UIView()
        scrollView.addSubview(fakeView)
        fakeView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.width.equalToSuperview()
            make.top.equalToSuperview()
            make.height.equalTo(0)
        }
        
        let cover = buildCover()
        scrollView.addSubview(cover)
        cover.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.top.equalToSuperview()
        }
        
        let gameView = buildExtraInfoView()
        scrollView.addSubview(gameView)
        gameView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.top.equalTo(cover.snp.bottom).offset(-52)
            make.bottom.equalToSuperview()
        }
        
        let userInfoView = buildUserInfoView()
        scrollView.addSubview(userInfoView)
        userInfoView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.bottom.equalTo(gameView.snp.top).offset(-10)
        }
        
        scrollView.addSubview(voiceBar)
        voiceBar.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(16)
            make.bottom.equalTo(userInfoView.snp.top).offset(-8)
        }
        
        scrollView.addSubview(inRoomView)
        inRoomView.snp.makeConstraints { make in
            make.trailing.equalToSuperview()
            make.bottom.equalTo(userInfoView.snp.bottom).offset(-40)
        }
        
        let menu = buildBottomMenu()
        view.addSubview(menu)
        menu.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.bottom.equalToSuperview()
        }
        
        scoreView.isHidden = true
        view.addSubview(scoreView)
        scoreView.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.trailing.equalToSuperview().offset(-8)
        }
        
        infoView.outerScrollView = scrollView
    }
    
    func buildCover() -> UIView {
        let coverGradient = CAGradientLayer()
        coverGradient.colors = [UIColor.black.withAlphaComponent(0).cgColor, UIColor.black.cgColor]
        coverGradient.locations = [0, 1]
        coverGradient.startPoint = .init(x: 0, y: 0)
        coverGradient.endPoint = .init(x: 0, y: 1)
        cover.layer.addSublayer(coverGradient)
        cover.publisher(for: \.bounds).removeDuplicates().sink { [weak coverGradient] newValue in
            guard let coverGradient else { return }
            coverGradient.frame = .init(
                x: 0,
                y: newValue.height * 0.5,
                width: newValue.width,
                height: newValue.height * 0.5
            )
        }.store(in: &cancellables)
        
        cover.contentMode = .scaleAspectFill
        cover.onTap { [weak self] in
            guard let self else { return }
            guard let detail else { return }
            guard !detail.avatar.isEmpty else { return }
            view.presentImagePreview([detail.avatar], 0)
        }
        cover.snp.makeConstraints { make in
            make.height.equalTo(cover.snp.width).multipliedBy(363.0/375.0)
        }
        
        
        return cover
    }
    
    func buildUserInfoView() -> UIView {
        
        return userInfoView
    }
    
    func buildExtraInfoView() -> UIView {
        infoView.outerScrollView = scrollView
        
        return infoView
    }
    
    func buildBottomMenu() -> UIView {
        return bottomMenu
    }
    
    func setupNavBar() {
        navigationBarColor = .clear
        
        let menu = buildButtonMenu()
        setRightButton(menu)
        
        let container = UIView()
        avatar.alpha = 0.0
        avatar.layer.cornerRadius = 16
        avatar.clipsToBounds = true
        container.addSubview(avatar)
        avatar.snp.makeConstraints { make in
            make.leading.equalToSuperview()
            make.centerY.equalToSuperview()
            make.width.height.equalTo(32)
        }
        
        titleLabel.alpha = 0.0
        titleLabel.font = .heading_h3
        titleLabel.textColor = .text_5
        titleLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
        titleLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        container.addSubview(titleLabel)
        titleLabel.snp.makeConstraints { make in
            make.leading.equalTo(avatar.snp.trailing).offset(12)
            make.centerY.equalToSuperview()
            make.trailing.lessThanOrEqualToSuperview().offset(-37)
        }
        
        setTitleView(container)
        container.snp.makeConstraints { make in
            make.width.equalTo(view.bounds.width).priority(.medium)
            make.height.equalTo(44)
        }
        
        updateProgress(0.0)
    }
    
    func buildButtonMenu() -> UIView {
        let stackView = UIStackView()
        stackView.axis = .horizontal
        stackView.spacing = 14
        
        shareButton.layer.cornerRadius = 16
        shareButton.isHidden = true
        shareButton.setImage(.icShare.withRenderingMode(.alwaysTemplate), for: .normal)
        shareButton.snp.makeConstraints { make in
            make.width.height.equalTo(32)
        }
        shareButton.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            view.pushToPostShare()
        }), for: .touchUpInside)
        stackView.addArrangedSubview(shareButton)
        
        let editButton = buildEditButton()
        stackView.addArrangedSubview(editButton)
        
        moreButton.layer.cornerRadius = 16
        moreButton.isHidden = true
        moreButton.setImage(.icMore.withRenderingMode(.alwaysTemplate), for: .normal)
        moreButton.snp.makeConstraints { make in
            make.width.height.equalTo(32)
        }
        moreButton.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            showMoreMenu()
        }), for: .touchUpInside)
        stackView.addArrangedSubview(moreButton)
        
        return stackView
    }
    
    func buildEditButton() -> UIView {
        editButton.isHidden = true
        editButton.layer.cornerRadius = 16
        editButton.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            view.pushToEditProfile()
        }), for: .touchUpInside)
        editButton.snp.makeConstraints { make in
            make.height.equalTo(32)
        }
        
        let stackView = UIStackView()
        stackView.isUserInteractionEnabled = false
        stackView.axis = .horizontal
        stackView.spacing = 3
        
        editButton.addSubview(stackView)
        stackView.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.horizontalEdges.equalToSuperview().inset(9)
        }
        
        editIc.image = .icEditClear.withRenderingMode(.alwaysTemplate)
        stackView.addArrangedSubview(editIc)
        
        editLabel.text = .init(key: "A00226")
        editLabel.font = .body_m
        editLabel.textColor = .text_1
        stackView.addArrangedSubview(editLabel)
        
        return editButton
    }
}
