//
//  LNSkillDetailViewController.swift
//  Lanu
//
//  Created by OneeChan on 2025/11/28.
//

import Foundation
import UIKit
import SnapKit
import Combine
import AutoCodable


extension UIView {
    func pushToSkillDetail(_ skillId: String) {
        let vc = LNSkillDetailViewController(skillId: skillId)
        navigationController?.pushViewController(vc, animated: true)
    }
}


class LNSkillDetailViewController: LNViewController {
    private let skillId: String
    
    private let avatar = UIImageView()
    private let titleLabel = UILabel()
    private let followButton = UIButton()
    private let profileButton = UIButton()
    private let moreButton = UIButton()
    
    private let cover = UIImageView()
    private let userInfoView = LNSkillUserInfoView()
    private let gameNameLabel = UILabel()
    private let descLabel = UILabel()
    private let tagView = LNSkillTagView()
    private let photosView = LNSkillPhotosView()
    private let commentsView = LNSkillCommentsView()
    private let bottomMenu = LNSkillBottomMenuView()
    
    private var detail: LNGameMateSkillDetailVO?
    private var stayTimer: String?
    
    init(skillId: String) {
        self.skillId = skillId
        
        super.init(nibName: nil, bundle: nil)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupViews()
        
        loadSkillInfo()
        
        LNEventDeliver.addObserver(self)
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        if detail?.userNo.isMyUid == true {
            loadSkillInfo()
        } else {
            triggerAutoReplay()
        }
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        LNDelayTask.cancel(key: stayTimer)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

private extension LNSkillDetailViewController {
    func triggerAutoReplay() {
        guard let uid = detail?.userNo else { return }
        if !uid.isMyUid {
            stayTimer = LNDelayTask.perform(delay: 3) { [weak self] in
                guard let self else { return }
                LNGameMateManager.shared.triggerAutoReplayIfNeed(uid: uid)
            }
        }
    }
    
    func loadSkillInfo() {
        LNGameMateManager.shared.getSkillDetail(skillId: skillId) { [weak self] info in
            guard let self else { return }
            guard let info else { return }
            if detail == nil {
                LNStatisticManager.shared.reportVisitor(uid: info.userNo) { _ in }
                LNStatisticManager.shared.reportViewPlaymate(uid: info.userNo)
            }
            self.detail = info
            
            cover.sd_setImage(with: URL(string: info.cover.isEmpty ? info.avatar : info.cover))
            userInfoView.update(info)
            gameNameLabel.text = info.categoryName
            
            descLabel.isHidden = info.summary.isEmpty
            descLabel.text = info.summary
            
            tagView.update(info.labels)
            photosView.update(info)
            
            commentsView.update(info)
            
            bottomMenu.update(info)
            
            avatar.showAvatar(info.avatar)
            titleLabel.text = info.nickname
            followButton.isHidden = info.follow || info.userNo.isMyUid
            moreButton.isHidden = info.userNo.isMyUid
            
            triggerAutoReplay()
        }
    }
}

extension LNSkillDetailViewController: LNRelationManagerNotify {
    func onUserRelationChanged(uid: String, relation: LNUserRelationShip) {
        guard uid == detail?.userNo else { return }
        
        followButton.isHidden = relation.contains(.followed)
    }
}

extension LNSkillDetailViewController: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let offset = cover.bounds.height - 35 - 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)
    }
}

extension LNSkillDetailViewController {
    private func showMoreMenu() {
        let panel = LNBottomSheetMenu()
        panel.update([
            .init(key: "A00043"),
            detail?.userNo.isInMyBlackList != true ? .init(key: "A00044") : .init(key: "A00045")
        ]) { [weak self] index, _ in
            guard let self else { return }
            guard let detail else { return }
            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()
    }
    
    private 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
        followButton.tintColor = tintColor
        profileButton.tintColor = tintColor
        moreButton.tintColor = tintColor
        
        let background = UIColor.black.withAlphaComponent(0.4 * (1 - progress))
        followButton.backgroundColor = background
        profileButton.backgroundColor = background
        moreButton.backgroundColor = background
    }
    
    private func setupViews() {
        setupNavBar()
        
        let stackView = UIStackView()
        stackView.axis = .vertical
        view.addSubview(stackView)
        stackView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.top.equalTo(fakeNaviBgView)
            make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom)
        }
        
        let scrollView = UIScrollView()
        scrollView.delegate = self
        scrollView.clipsToBounds = false
        scrollView.backgroundColor = .fill
        scrollView.contentInsetAdjustmentBehavior = .never
        scrollView.showsVerticalScrollIndicator = false
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.contentInset = .init(top: 0, left: 0, bottom: -view.commonBottomInset + 47, right: 0)
        stackView.addArrangedSubview(scrollView)
        
        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 = buildGameView()
        scrollView.addSubview(gameView)
        gameView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.top.equalTo(cover.snp.bottom).offset(-35)
            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)
        }
        
        let menu = buildBottomMenu()
        view.addSubview(menu)
        menu.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.bottom.equalToSuperview()
        }
    }
    
    private func setupNavBar() {
        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)
    }
    
    private func buildButtonMenu() -> UIView {
        let stackView = UIStackView()
        stackView.axis = .horizontal
        stackView.spacing = 14
        
        followButton.layer.cornerRadius = 16
        followButton.isHidden = true
        followButton.setImage(.icSkillFollow.withRenderingMode(.alwaysTemplate), for: .normal)
        followButton.snp.makeConstraints { make in
            make.width.height.equalTo(32)
        }
        followButton.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            guard let detail else { return }
            LNRelationManager.shared.operateFollow(uid: detail.userNo, follow: true, handler: nil)
        }), for: .touchUpInside)
        stackView.addArrangedSubview(followButton)
        
        profileButton.layer.cornerRadius = 16
        profileButton.setImage(.icSkillToProfile.withRenderingMode(.alwaysTemplate), for: .normal)
        profileButton.snp.makeConstraints { make in
            make.width.height.equalTo(32)
        }
        profileButton.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            guard let detail else { return }
            view.pushToProfile(uid: detail.userNo)
        }), for: .touchUpInside)
        stackView.addArrangedSubview(profileButton)
        
        moreButton.layer.cornerRadius = 16
        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
    }
    
    private 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.clipsToBounds = true
        cover.onTap { [weak self] in
            guard let self else { return }
            guard let cover = detail?.cover.isEmpty != false ? detail?.avatar : detail?.cover else { return }
            view.presentImagePreview([cover], 0)
        }
        cover.snp.makeConstraints { make in
            make.height.equalTo(cover.snp.width).multipliedBy(363.0/375.0)
        }
        
        return cover
    }
    
    private func buildUserInfoView() -> UIView {
        
        return userInfoView
    }
    
    private func buildGameView() -> UIView {
        let container = UIView()
        container.backgroundColor = .fill
        container.layer.cornerRadius = 20
        container.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
        
        gameNameLabel.font = .heading_h3
        gameNameLabel.textColor = .text_5
        container.addSubview(gameNameLabel)
        gameNameLabel.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(16)
            make.top.equalToSuperview().offset(16)
        }
        
        let line = UIView()
        line.backgroundColor = .fill_2
        container.addSubview(line)
        line.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview().inset(16)
            make.top.equalTo(gameNameLabel.snp.bottom).offset(10)
            make.height.equalTo(1)
        }
        
        let stackView = UIStackView()
        stackView.axis = .vertical
        stackView.spacing = 12
        container.addSubview(stackView)
        stackView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview().inset(16)
            make.top.equalTo(line.snp.bottom).offset(10)
            make.bottom.equalToSuperview()
        }
        
        descLabel.font = .body_m
        descLabel.textColor = .text_4
        descLabel.numberOfLines = 0
        descLabel.isHidden = true
        stackView.addArrangedSubview(descLabel)
        
        tagView.isHidden = true
        stackView.addArrangedSubview(tagView)
        
        photosView.isHidden = true
        stackView.addArrangedSubview(photosView)
        
        commentsView.isHidden = true
        stackView.addArrangedSubview(commentsView)
        
        return container
    }
    
    private func buildBottomMenu() -> UIView {
        
        return bottomMenu
    }
}


#if DEBUG

import SwiftUI

struct LNSkillDetailViewControllerPreview: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> some UIViewController {
        LNNavigationController(rootViewController: LNSkillDetailViewController(skillId: ""))
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) { }
}

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