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

import Foundation
import UIKit
import SnapKit
import Combine


class LNJoinUsSkillFieldsEditView: UIView {
    private let titleLabel = UILabel()
    
    private let stackView = UIStackView()
    
    private let applyButton = UIButton()
    
    private var fieldViews: [LNSkillFieldBaseEditView] = []
    private var field: LNCreateSkillInputFieldsVO?
    
    override var isHidden: Bool {
        didSet {
            if isHidden {
                LNVoicePlayer.shared.stop()
                LNVoiceRecorder.shared.stopRecord()
            }
        }
    }
    
    deinit {
        LNVoicePlayer.shared.stop()
        LNVoiceRecorder.shared.stopRecord()
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        setupViews()
    }
    
    func update(_ skill: LNGameCategoryItemVO, info: LNCreateSkillInputFieldsVO) {
        stackView.arrangedSubviews.forEach {
            stackView.removeArrangedSubview($0)
            $0.removeFromSuperview()
        }
        
        titleLabel.text = skill.name
        if info.bizCategoryCode?.isEmpty != false {
            info.bizCategoryCode = skill.code
        }
        
        for field in info.fields {
            let view: LNSkillFieldBaseEditView? = switch field.type {
            case .singleLineText, .number:
                LNSkillFieldSingleLineEditView()
            case .multiLineText:
                LNSkillFieldMultiLineEditView()
            case .singleSelection, .multiSelection:
                LNSkillFieldSelectionEditView()
            case .voice:
                LNSkillFieldVoiceEditView()
            case .photo:
                LNSkillFieldPhotoEditView()
            default:
                nil
            }
            if let view {
                stackView.addArrangedSubview(view)
                fieldViews.append(view)
                view.delegate = self
                view.update(field)
            }
        }
        
        field = info
        
        checkSubmitButton()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension LNJoinUsSkillFieldsEditView {
    private func commit() {
        guard let field else { return }
        
        if fieldViews.first(where: { $0.checkAvailable() == false }) != nil {
            return
        }
        showLoading()
        DispatchQueue.global().async { [weak self] in
            let voices = field.fields.filter({ $0.type == .voice })
            let group = DispatchGroup()
            var uploadDone = true
            for voice in voices {
                if let path = voice.value as? String,
                    !path.starts(with: "http") {
                    group.enter()
                    LNFileUploader.shared.startUpload(type: .voice, fileURL: URL(fileURLWithPath: path), progressHandler: nil)
                    { url, err in
                        if let err {
                            showToast(err)
                            uploadDone = false
                        } else if let url {
                            voice.value = url
                        } else {
                            uploadDone = false
                        }
                        group.leave()
                    }
                }
            }
            group.wait()
            
            if !uploadDone {
                dismissLoading()
                return
            }
            guard let self else { return }
            let info = LNCreateSkillFieldsInfo()
            info.bizCategoryCode = field.bizCategoryCode!
            for item in field.fields {
                let config = LNCreateSkillFieldInfo()
                config.fieldCode = item.fieldCode
                config.value = item.value
                if item.type == .voice {
                    config.duration = item.duration
                }
                info.fields.append(config)
            }
            LNGameMateManager.shared.createSkill(info: info) { [weak self] success in
                dismissLoading()
                guard let self else { return }
                guard success else { return }
                pushToJoinUsReview()
            }
        }
    }
}

extension LNJoinUsSkillFieldsEditView: LNSkillFieldBaseEditViewDelegate {
    func onSkillFieldBaseEditViewInputChanged(view: LNSkillFieldBaseEditView) {
        checkSubmitButton()
    }
}

extension LNJoinUsSkillFieldsEditView {
    private func checkSubmitButton() {
        let allInput = fieldViews.first { !$0.hasInput() } == nil
        
        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)
        }
        
        let header = buildTitle()
        addSubview(header)
        header.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.top.equalToSuperview()
        }
        
        let scrollView = UIScrollView()
        scrollView.showsVerticalScrollIndicator = false
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.contentInsetAdjustmentBehavior = .never
        scrollView.contentInset = .init(top: 0, left: 0, bottom: -commonBottomInset + 62, right: 0)
        scrollView.adjustKeyoard()
        addSubview(scrollView)
        scrollView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview().inset(16)
            make.top.equalTo(header.snp.bottom)
            make.bottom.equalToSuperview()
        }
        
        stackView.axis = .vertical
        stackView.spacing = 24
        scrollView.addSubview(stackView)
        stackView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.width.equalToSuperview()
        }
        
        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: "A00240"), 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.isEnabled = false
        applyButton.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            commit()
        }), 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 buildTitle() -> UIView {
        let container = UIView()
        
        titleLabel.font = .heading_h2
        titleLabel.textColor = .text_5
        container.addSubview(titleLabel)
        titleLabel.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview().inset(20)
            make.verticalEdges.equalToSuperview().inset(20)
        }
        
        return container
    }
}
