//
//  LNSkillFieldVoiceEditView.swift
//  Gami
//
//  Created by OneeChan on 2026/1/21.
//

import Foundation
import UIKit
import SnapKit


class LNSkillFieldVoiceEditView: LNSkillFieldBaseEditView {
    private var minDuration: Double?
    private var maxDuration: Double?
    
    private let recordView = UIView()
    private let recordButton = UIButton()
    private let recordDurationLabel = UILabel()
    private let recordText = UILabel()
    private var recordTaskId: String?
    
    private let displayView = UIView()
    private let playIcon = UIImageView()
    private let voiceWaveView = LNVoiceWaveView()
    private let playDurationLabel = UILabel()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        setupViews()
        
        LNEventDeliver.addObserver(self)
    }
    
    override func update(_ field: LNSkillEditField) {
        super.update(field)
        
        if let limit = field.validate.size {
            minDuration = Double(limit.min)
            maxDuration = Double(limit.max)
        }
        
        if let url = field.value as? String, !url.isEmpty {
            recordView.isHidden = true
            displayView.isHidden = false
            if field.duration == 0 {
                LNVoiceResourceManager.shared.getRemoteAudioDuration(urlStr: url) { [weak self] duration, _ in
                    guard let self else { return }
                    guard let duration else { return }
                    guard field.value as? String == url else { return }
                    field.duration = duration.toDuration
                    playDurationLabel.text = "\(field.duration)“"
                }
            } else {
                playDurationLabel.text = "\(field.duration)“"
            }
        }
    }
    
    required init(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension LNSkillFieldVoiceEditView {
    private func handleRecordResult(url: URL?, duration: Double) {
        guard let url else {
            return
        }
        if let minDuration, duration < minDuration {
            showToast(.init(key: "B00009", minDuration))
            return
        }
        field?.value = url.path
        field?.duration = duration.toDuration
        playDurationLabel.text = duration.durationDisplay
        
        recordView.isHidden = true
        resetRecord()
        displayView.isHidden = false
        
        needReview = true
        delegate?.onSkillFieldBaseEditViewInputChanged(view: self)
    }
}

extension LNSkillFieldVoiceEditView: LNVoicePlayerNotify {
    func onAudioUpdateDuration(path: String, cur: TimeInterval, total: TimeInterval) {
        guard field?.value as? String == path else { return }
        
        playDurationLabel.text = (total - cur).durationDisplay
    }
    
    func onAudioStopPlay(path: String) {
        guard field?.value as? String == path else { return }
        
        guard let curDuration = field?.duration else { return }
        
        playDurationLabel.text = "\(curDuration)“"
        playIcon.image = .icVoicePlay
        voiceWaveView.stopAnimate()
    }
    
    func onAudioStartPlay(path: String) {
        guard field?.value as? String == path else { return }
        
        playIcon.image = .icVoicePause
        voiceWaveView.startAnimate()
    }
}

extension LNSkillFieldVoiceEditView: LNVoiceRecorderNotify {
    func onRecordTaskDurationChanged(taskId: String, duration: Double, volumeRatio: Double) {
        guard recordTaskId == taskId else { return }
        
        recordDurationLabel.text = duration.timeCountDisplay
    }
    
    func onRecordTaskRecording(taskId: String) {
        guard recordTaskId == taskId else { return }
        
        recordText.text = .init(key: "B00008")
        recordButton.setImage(.icVoiceEditStop, for: .normal)
    }
    
    func onRecordTaskStop(taskId: String) {
        guard recordTaskId == taskId else { return }
        
        resetRecord()
    }
    
    func onRecordTaskReachMaxDuration(taskId: String, fileUrl: URL?, duration: Double) {
        guard recordTaskId == taskId else { return }
        
        handleRecordResult(url: fileUrl, duration: duration)
    }
}

extension LNSkillFieldVoiceEditView {
    private func resetRecord() {
        recordDurationLabel.text = "00:00"
        recordButton.setImage(.icVoiceEditStart, for: .normal)
        recordText.text = .init(key: "B00007")
    }
    
    private func setupViews() {
        container.layer.cornerRadius = 12
        container.backgroundColor = .fill_1
        container.snp.makeConstraints { make in
            make.height.equalTo(158)
        }
        
        let recordView = buildRecordView()
        container.addSubview(recordView)
        recordView.snp.makeConstraints { make in
            make.center.equalToSuperview()
        }
        
        let playView = buildDisplayView()
        container.addSubview(playView)
        playView.snp.makeConstraints { make in
            make.center.equalToSuperview()
        }
    }
    
    private func buildRecordView() -> UIView {
        recordDurationLabel.font = .body_m
        recordDurationLabel.textColor = .text_5
        recordView.addSubview(recordDurationLabel)
        recordDurationLabel.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            make.top.equalToSuperview()
        }
        
        recordView.addSubview(recordButton)
        recordButton.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            LNVoicePlayer.shared.stop()
            
            if LNVoiceRecorder.shared.isRecording {
                let (url, duration) = LNVoiceRecorder.shared.stopRecord()
                handleRecordResult(url: url, duration: duration)
            } else {
                LNVoiceRecorder.shared.startRecord(maxDuration) { [weak self] taskId in
                    guard let self else { return }
                    recordTaskId = taskId
                }
            }
        }), for: .touchUpInside)
        recordButton.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            make.top.equalTo(recordDurationLabel.snp.bottom).offset(12)
            make.leading.greaterThanOrEqualToSuperview()
        }
        
        recordText.font = .body_m
        recordText.textColor = .text_4
        recordView.addSubview(recordText)
        recordText.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.top.equalTo(recordButton.snp.bottom).offset(12)
            make.bottom.equalToSuperview()
        }
        
        resetRecord()
        
        return recordView
    }
    
    private func buildDisplayView() -> UIView {
        displayView.isHidden = true
        
        let playView = UIView()
        displayView.addSubview(playView)
        playView.snp.makeConstraints { make in
            make.verticalEdges.equalToSuperview()
            make.leading.equalToSuperview()
        }
        
        let button = UIButton()
        button.setBackgroundImage(.primary_7, for: .normal)
        button.layer.cornerRadius = 19
        button.clipsToBounds = true
        playView.addSubview(button)
        button.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.top.equalToSuperview()
            make.width.equalTo(206)
            make.height.equalTo(38)
        }
        
        playIcon.image = .icVoicePlay
        button.addSubview(playIcon)
        playIcon.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.leading.equalToSuperview().offset(3)
            make.width.height.equalTo(32)
        }
        
        voiceWaveView.isUserInteractionEnabled = false
        voiceWaveView.itemWidth = 3
        voiceWaveView.build()
        button.addSubview(voiceWaveView)
        voiceWaveView.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.leading.equalTo(playIcon.snp.trailing).offset(7)
            make.width.equalTo(30)
            make.height.equalTo(18)
        }
        
        playDurationLabel.font = .heading_h4
        playDurationLabel.textColor = .text_1
        button.addSubview(playDurationLabel)
        playDurationLabel.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.trailing.equalToSuperview().offset(-8)
        }
        
        button.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            if LNVoicePlayer.shared.isPlaying {
                LNVoicePlayer.shared.stop()
            } else if let path = field?.value as? String {
                LNVoicePlayer.shared.play(path: path)
            }
        }), for: .touchUpInside)
        
        let playLabel = UILabel()
        playLabel.text = .init(key: "B00011")
        playLabel.font = .body_s
        playLabel.textColor = .text_4
        playLabel.textAlignment = .center
        playView.addSubview(playLabel)
        playLabel.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.bottom.equalToSuperview()
            make.top.equalTo(button.snp.bottom).offset(11)
        }
        
        let redoView = UIView()
        displayView.addSubview(redoView)
        redoView.snp.makeConstraints { make in
            make.verticalEdges.equalToSuperview()
            make.trailing.equalToSuperview()
            make.leading.equalTo(playView.snp.trailing).offset(13)
            make.width.equalTo(60)
        }
        
        let config = UIImage.SymbolConfiguration(pointSize: 18, weight: .semibold)
        let redoButton = UIButton()
        redoButton.backgroundColor = .fill_4
        redoButton.layer.cornerRadius = 17
        redoButton.setImage(.init(systemName: "xmark", withConfiguration: config)?.withRenderingMode(.alwaysTemplate), for: .normal)
        redoButton.tintColor = .fill
        redoButton.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            LNVoicePlayer.shared.stop()
            field?.value = nil
            field?.duration = 0
            
            recordView.isHidden = false
            displayView.isHidden = true
        }), for: .touchUpInside)
        redoView.addSubview(redoButton)
        redoButton.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            make.top.equalToSuperview()
            make.width.height.equalTo(34)
        }
        
        let redoLabel = UILabel()
        redoLabel.text = .init(key: "B00010")
        redoLabel.font = .body_s
        redoLabel.textColor = .text_4
        redoLabel.textAlignment = .center
        redoView.addSubview(redoLabel)
        redoLabel.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.bottom.equalToSuperview()
        }
        
        return displayView
    }
}
