//
//  LNVoiceEditView.swift
//  Gami
//
//  Created by OneeChan on 2026/3/10.
//

import Foundation
import UIKit
import SnapKit


protocol LNVoiceEditViewDelegate: AnyObject {
    func onVoiceChanged()
}


class LNVoiceEditView: UIView {
    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 playVoiceView = LNVoicePlayView()
    private(set) var hasChanged = false
    
    weak var delegate: LNVoiceEditViewDelegate?
    
    var voiceInfo: (String?, Int) {
        (playVoiceView.curUrl, playVoiceView.duration)
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        setupViews()
        LNEventDeliver.addObserver(self)
    }
    
    func update(_ url: String, duration: Int) {
        playVoiceView.update(url, duration: duration)
        
        recordView.isHidden = true
        displayView.isHidden = true
        if url.isEmpty || duration == 0 {
            recordView.isHidden = false
        } else {
            displayView.isHidden = false
        }
    }
    
    override func didMoveToWindow() {
        super.didMoveToWindow()
        
        if window == nil, recordTaskId != nil {
            LNVoiceRecorder.shared.stopRecord()
        }
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension LNVoiceEditView {
    private func handleRecordResult(url: URL?, duration: Double) {
        guard let url else {
            return
        }
        if let minDuration, duration < minDuration {
            showToast(.init(key: "B00009", minDuration))
            return
        }
        playVoiceView.update(url.path, duration: duration.toDuration)
        
        recordView.isHidden = true
        resetRecord()
        displayView.isHidden = false
        
        hasChanged = true
        delegate?.onVoiceChanged()
    }
}

extension LNVoiceEditView: 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 LNVoiceEditView {
    private func resetRecord() {
        recordDurationLabel.text = "00:00"
        recordButton.setImage(.icVoiceEditStart, for: .normal)
        recordText.text = .init(key: "B00007")
        recordTaskId = nil
    }
    
    private func setupViews() {
        layer.cornerRadius = 12
        backgroundColor = .fill_1
        snp.makeConstraints { make in
            make.height.equalTo(158).priority(.low)
        }
        
        let recordView = buildRecordView()
        addSubview(recordView)
        recordView.snp.makeConstraints { make in
            make.center.equalToSuperview()
        }
        
        let playView = buildDisplayView()
        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()
        }
        
        playVoiceView.waveView.itemWidth = 3
        playVoiceView.waveView.build()
        playVoiceView.waveView.snp.updateConstraints { make in
            make.width.equalTo(30)
            make.height.equalTo(18)
        }
        playVoiceView.layer.cornerRadius = 19
        playVoiceView.clipsToBounds = true
        playView.addSubview(playVoiceView)
        playVoiceView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.top.equalToSuperview()
            make.width.equalTo(206)
            make.height.equalTo(38)
        }
        
        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(playVoiceView.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()
            playVoiceView.update(nil, duration: 0)
            
            recordView.isHidden = false
            displayView.isHidden = true
            
            delegate?.onVoiceChanged()
        }), 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
    }
}
