//
//  LNJoinUsInputInfoView.swift
//  Gami
//
//  Created by OneeChan on 2026/1/19.
//

import Foundation
import UIKit
import SnapKit
import Combine


protocol LNJoinUsInputInfoViewDelegate: AnyObject {
    func joinUsInputInfoViewDidFinish(view: LNJoinUsInputInfoView)
}


class LNJoinUsInputInfoView: UIView {
    private let scrollView = UIScrollView()
    
    private let avatar = LNImageUploadView()
    
    private let nameInput = UITextField()
    private let nameCountLabel = UILabel()
    
    private let maleButton = UIButton()
    private let femaleButton = UIButton()
    private var gender: LNUserGender = .unknow {
        didSet {
            maleButton.backgroundColor = gender == .male ? .fill_5 : .primary_1
            femaleButton.backgroundColor = gender == .female ? .fill_5 : .primary_1
        }
    }
    
    private let birthdayLabel = UILabel()
    private var birthday: Double = 0 {
        didSet {
            birthdayLabel.text = birthday.formattedFullDate("-")
        }
    }
    
    private let languageLabel = UILabel()
    private var curLanguages: [LNLanguageConstsVO] = [] {
        didSet {
            languageLabel.text = curLanguages.map({ $0.name }).joined(separator: ",")
        }
    }
    
    private let bioInput = LNCommonTextView()
    
    private let applyButton = UIButton()
    
    weak var delegate: LNJoinUsInputInfoViewDelegate?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        setupViews()
    }
    
    func update(_ info: LNJoinUsBaseInfoVO) {
        avatar.loadImage(url:info.avatar)
        nameInput.text = info.nickname
        gender = info.gender
        bioInput.setText(info.intro)
        
        var languages: [LNLanguageConstsVO] = []
        for language in info.languageCodes {
            if let item = LNConfigManager.shared.commonConfig.commonLanguageConsts.first(where: { $0.code == language }) {
                languages.append(item)
            }
        }
        curLanguages = languages
        
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        if let date = dateFormatter.date(from: info.birthday) {
            birthday = date.timeIntervalSince1970
        } else {
            birthday = Double(myUserInfo.birthday / 1_000)
        }
        
        checkSaveButton()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension LNJoinUsInputInfoView: LNImageUploadViewDelegate {
    func onImageUploadView(view: LNImageUploadView, didUploadImage url: String) {
        checkSaveButton()
    }
}

extension LNJoinUsInputInfoView: UITextFieldDelegate, UITextViewDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let currentText = textField.text ?? ""
                
        guard let range = Range(range, in: currentText) else { return false }
        let newText = currentText.replacingCharacters(in: range, with: string)
        if newText.count < currentText.count {
            return true
        }
        
        return newText.count <= LNProfileManager.nameMaxInput
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
    
    func textViewDidChange(_ textView: UITextView) {
        checkSaveButton()
    }
}

extension LNJoinUsInputInfoView {
    private func checkSaveButton() {
        let allInput = avatar.imageUrl?.isEmpty == false
        && nameInput.text?.isEmpty == false
        && gender != .unknow
        && birthday != 0
        && !curLanguages.isEmpty
        && bioInput.textView.text.isEmpty == false
        
        if allInput != applyButton.isEnabled {
            applyButton.isEnabled = allInput
            applyButton.setBackgroundImage(allInput ? .primary_8 : nil, for: .normal)
        }
    }
    
    private func setupViews() {
        onTap { [weak self] in
            guard let self else { return }
            endEditing(true)
        }
        
        scrollView.showsVerticalScrollIndicator = false
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.contentInset = .init(top: 0, left: 0, bottom: -commonBottomInset + 32 + 47, right: 0)
        scrollView.adjustKeyoard()
        addSubview(scrollView)
        scrollView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview().inset(16)
            make.top.equalToSuperview().offset(20)
            make.bottom.equalToSuperview()
        }
        
        let stackView = UIStackView()
        stackView.axis = .vertical
        stackView.spacing = 24
        scrollView.addSubview(stackView)
        stackView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.width.equalToSuperview()
        }
        
        stackView.addArrangedSubview(buildAvatarView())
        stackView.addArrangedSubview(buildNickNameView())
        stackView.addArrangedSubview(buildGenderView())
        stackView.addArrangedSubview(buildBirthdayView())
        stackView.addArrangedSubview(buildLanguageView())
        stackView.addArrangedSubview(buildBioView())
        
        let bottomMenu = UIView()
        addSubview(bottomMenu)
        bottomMenu.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.bottom.equalToSuperview()
        }
        
        let bottomGradient = CAGradientLayer()
        bottomGradient.colors = [
            UIColor.white.withAlphaComponent(0).cgColor,
            UIColor.white.cgColor,
            UIColor.white.cgColor
        ]
        bottomGradient.locations = [0, 0.5, 1]
        bottomGradient.startPoint = .init(x: 0, y: 0)
        bottomGradient.endPoint = .init(x: 0, y: 1)
        bottomMenu.layer.addSublayer(bottomGradient)
        bottomMenu.publisher(for: \.bounds).removeDuplicates().sink { [weak bottomGradient] newValue in
            guard let bottomGradient else { return }
            bottomGradient.frame = newValue
        }.store(in: &cancellables)
        
        applyButton.setTitle(.init(key: "B00045"), for: .normal)
        applyButton.setTitleColor(.text_1, for: .normal)
        applyButton.titleLabel?.font = .heading_h3
        applyButton.layer.cornerRadius = 23.5
        applyButton.backgroundColor = .fill_4
        applyButton.clipsToBounds = true
        applyButton.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            guard let avatarUrl = avatar.imageUrl,
                  let name = nameInput.text else {
                return
            }
            
            let config = LNJoinUsBaseInfoVO()
            config.avatar = avatarUrl
            config.nickname = name
            config.gender = gender
            config.birthday = birthday.formattedFullDate("-", normal: true)
            config.languageCodes = curLanguages.map({ $0.code })
            config.intro = bioInput.textView.text
            
            LNGameMateManager.shared.setJoinGameMateBaseInfo(info: config) { [weak self] success in
                guard let self, success else { return }
                delegate?.joinUsInputInfoViewDidFinish(view: self)
            }
        }), for: .touchUpInside)
        bottomMenu.addSubview(applyButton)
        applyButton.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview().inset(16)
            make.bottom.equalToSuperview().offset(commonBottomInset)
            make.top.equalToSuperview()
            make.height.equalTo(47)
        }
    }
    
    private func buildAvatarView() -> UIView {
        let groupView = LNJoinUsInputFieldGroupView()
        groupView.titleLabel.text = .init(key: "B00036")
        groupView.descLabel.text = .init(key: "B00037")
        groupView.showExample {
            let panel = LNJoinUsAvatarExamplePanel()
            panel.popup()
        }
        
        avatar.uploadType = .avatar
        avatar.backgroundColor = .fill_2
        avatar.layer.cornerRadius = 11
        avatar.clipsToBounds = true
        avatar.contentMode = .scaleAspectFill
        avatar.showClearButton = false
        avatar.showDefault = true
        avatar.delegate = self
        avatar.onTap { [weak self] in
            guard let self else { return }
            LNBottomSheetMenu.showImageSelectMenu(view: self, options: .init(allowEdit: true))
            { [weak self] image, _ in
                guard let self else { return }
                guard let image = image?.compress(type: .avatar) else { return }
                avatar.uploadImage(image: image)
            }
        }
        groupView.container.addSubview(avatar)
        avatar.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            make.verticalEdges.equalToSuperview()
            make.width.height.equalTo(105)
        }
        return groupView
    }
    
    private func buildNickNameView() -> UIView {
        let groupView = LNJoinUsInputFieldGroupView()
        groupView.titleLabel.text = .init(key: "A00188")
        groupView.descLabel.text = .init(key: "B00038")
        
        let container = UIView()
        container.backgroundColor = .fill_2
        container.layer.cornerRadius = 19
        groupView.container.addSubview(container)
        container.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.height.equalTo(38)
        }
        
        nameCountLabel.font = .body_m
        nameCountLabel.textColor = .text_2
        container.addSubview(nameCountLabel)
        nameCountLabel.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.trailing.equalToSuperview().offset(-16)
        }
        
        nameInput.font = .body_m
        nameInput.textColor = .text_5
        nameInput.placeholder = .init(key: "B00043")
        nameInput.delegate = self
        nameInput.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            nameCountLabel.text = "\(nameInput.text?.count ?? 0)/\(LNProfileManager.nameMaxInput)"
        }), for: .editingChanged)
        container.addSubview(nameInput)
        nameInput.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(16)
            make.centerY.equalToSuperview()
            make.trailing.equalTo(nameCountLabel.snp.leading).offset(-16)
        }
        
        return groupView
    }
    
    private func buildGenderView() -> UIView {
        let groupView = LNJoinUsInputFieldGroupView()
        groupView.titleLabel.text = .init(key: "A00032")
        groupView.descLabel.text = .init(key: "B00039")
        
        let stackView = UIStackView()
        stackView.spacing = 23
        stackView.distribution = .fillEqually
        groupView.container.addSubview(stackView)
        stackView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        
        maleButton.setImage(.icGenderMale, for: .normal)
        maleButton.setTitle(.init(key: "A00014"), for: .normal)
        maleButton.setTitleColor(.text_5, for: .normal)
        maleButton.titleLabel?.font = .heading_h4
        maleButton.backgroundColor = .primary_1
        maleButton.layer.cornerRadius = 20
        maleButton.titleEdgeInsets = .init(top: 0, left: 8, bottom: 0, right: 0)
        maleButton.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            gender = .male
            checkSaveButton()
        }), for: .touchUpInside)
        stackView.addArrangedSubview(maleButton)
        maleButton.snp.makeConstraints { make in
            make.height.equalTo(40)
        }
        
        femaleButton.setImage(.icGenderFemale, for: .normal)
        femaleButton.setTitle(.init(key: "A00015"), for: .normal)
        femaleButton.setTitleColor(.text_5, for: .normal)
        femaleButton.titleLabel?.font = .heading_h4
        femaleButton.backgroundColor = .primary_1
        femaleButton.layer.cornerRadius = 20
        femaleButton.titleEdgeInsets = .init(top: 0, left: 8, bottom: 0, right: 0)
        femaleButton.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            gender = .female
            checkSaveButton()
        }), for: .touchUpInside)
        stackView.addArrangedSubview(femaleButton)
        femaleButton.snp.makeConstraints { make in
            make.height.equalTo(40)
        }
        
        return groupView
    }
    
    private func buildBirthdayView() -> UIView {
        let groupView = LNJoinUsInputFieldGroupView()
        groupView.titleLabel.text = .init(key: "A00205")
        groupView.descLabel.text = .init(key: "B00040")
        
        let container = UIView()
        container.backgroundColor = .fill_2
        container.layer.cornerRadius = 19
        container.onTap { [weak self] in
            guard let self else { return }
            let panel = LNDatePickerPanel()
            panel.setDefault(birthday)
            panel.handler = { [weak self] date in
                guard let self else { return }
                birthday = date
                checkSaveButton()
            }
            panel.popup()
        }
        groupView.container.addSubview(container)
        container.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.height.equalTo(38)
        }
        
        let arrow = UIImageView.arrowImageView(size: 15)
        arrow.tintColor = .text_3
        container.addSubview(arrow)
        arrow.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.trailing.equalToSuperview().offset(-16)
        }
        
        birthdayLabel.font = .heading_h4
        birthdayLabel.textColor = .text_5
        container.addSubview(birthdayLabel)
        birthdayLabel.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(16)
            make.centerY.equalToSuperview()
        }
        
        return groupView
    }
    
    private func buildLanguageView() -> UIView {
        let groupView = LNJoinUsInputFieldGroupView()
        groupView.titleLabel.text = .init(key: "A00256")
        groupView.descLabel.isHidden = true
        
        let container = UIView()
        container.backgroundColor = .fill_2
        container.layer.cornerRadius = 19
        container.onTap { [weak self] in
            guard let self else { return }
            let panel = LNLanguageSelectPanel()
            panel.update(curSelect: curLanguages)
            panel.handler = { [weak self] languages in
                guard let self else { return }
                curLanguages = languages
                checkSaveButton()
            }
            panel.popup()
        }
        groupView.container.addSubview(container)
        container.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.height.equalTo(38)
        }
        
        let arrow = UIImageView.arrowImageView(size: 15)
        arrow.tintColor = .text_3
        container.addSubview(arrow)
        arrow.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.trailing.equalToSuperview().offset(-16)
        }
        
        languageLabel.font = .heading_h4
        languageLabel.textColor = .text_5
        container.addSubview(languageLabel)
        languageLabel.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(16)
            make.centerY.equalToSuperview()
        }
        
        return groupView
    }
    
    private func buildBioView() -> UIView {
        let groupView = LNJoinUsInputFieldGroupView()
        groupView.titleLabel.text = .init(key: "B00042")
        groupView.descLabel.text = .init(key: "B00041")
        
        bioInput.placeholderLabel.text = .init(key: "B00044")
        bioInput.maxInput = LNProfileManager.bioMaxInput
        bioInput.delegate = self
        groupView.container.addSubview(bioInput)
        bioInput.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.height.equalTo(130)
        }
        
        return groupView
    }
}

#if DEBUG

import SwiftUI

struct LNJoinUsInputInfoViewPreview: UIViewRepresentable {
    func makeUIView(context: Context) -> some UIView {
        let container = UIView()
        container.backgroundColor = .fill
        
        let view = LNJoinUsInputInfoView()
        container.addSubview(view)
        view.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        
        return container
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) { }
}

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