//
//  ActiveCallViewController.swift
//  JJPhoneDemo
//
//

import UIKit
import AVFoundation

class ActiveCallViewController: UIViewController {
    
    var call: Call?
    
    private let phoneService: PhoneServiceProtocol = PhoneService.shared
    
    private var timer: Timer?
    private var callDuration: TimeInterval = 0
    private var callFailureCheckTimer: Timer?
    
    private let backgroundImageView: UIImageView = {
        let iv = UIImageView()
        iv.backgroundColor = UIConstants.Color.activeCallBackground
        iv.contentMode = .scaleAspectFill
        return iv
    }()
    
    private let nameLabel: UILabel = {
        let label = UILabel()
        label.textAlignment = .center
        if #available(iOS 13.0, *) {
            label.font = .systemFont(ofSize: 30, weight: .medium)
        } else {
            label.font = .systemFont(ofSize: 30, weight: .semibold)
        }
        label.textColor = .white
        return label
    }()
    
    private let statusLabel: UILabel = {
        let label = UILabel()
        label.textAlignment = .center
        if #available(iOS 13.0, *) {
            label.font = .systemFont(ofSize: 20, weight: .medium)
        } else {
            label.font = .systemFont(ofSize: 20, weight: .semibold)
        }
        label.textColor = .white
        label.text = "正在拨号"
        return label
    }()
    
    private let muteButton: UIButton = {
        let btn = UIButton(type: .custom)
        btn.backgroundColor = UIConstants.Color.activeCallButtonBackground
        btn.layer.cornerRadius = 37.5
        if #available(iOS 13.0, *) {
            btn.setImage(UIImage(systemName: "mic.slash.fill"), for: .normal)
            btn.setImage(UIImage(systemName: "mic.fill"), for: .selected)
        } else {
            btn.setTitle("🔇", for: .normal)
            btn.setTitle("🎤", for: .selected)
            btn.titleLabel?.font = .systemFont(ofSize: 24)
        }
        btn.tintColor = .white
        return btn
    }()
    
    private let speakerButton: UIButton = {
        let btn = UIButton(type: .custom)
        btn.backgroundColor = UIConstants.Color.activeCallButtonBackground
        btn.layer.cornerRadius = 37.5
        if #available(iOS 13.0, *) {
            btn.setImage(UIImage(systemName: "speaker.wave.2.fill"), for: .normal)
        } else {
            btn.setTitle("🔊", for: .normal)
            btn.titleLabel?.font = .systemFont(ofSize: 24)
        }
        btn.tintColor = .white
        return btn
    }()
    
    private let keyboardButton: UIButton = {
        let btn = UIButton(type: .custom)
        btn.backgroundColor = UIConstants.Color.activeCallButtonBackground
        btn.layer.cornerRadius = 37.5
        if #available(iOS 13.0, *) {
            btn.setImage(UIImage(systemName: "number"), for: .normal)
        } else {
            btn.setTitle("123", for: .normal)
            btn.titleLabel?.font = .systemFont(ofSize: 20, weight: .semibold)
        }
        btn.tintColor = .white
        return btn
    }()
    
    private let hangupButton: UIButton = {
        let btn = UIButton(type: .custom)
        btn.backgroundColor = .systemRed
        btn.layer.cornerRadius = 37.5
        if #available(iOS 13.0, *) {
            btn.setImage(UIImage(systemName: "phone.down.fill"), for: .normal)
        } else {
            btn.setTitle("📞", for: .normal)
            btn.titleLabel?.font = .systemFont(ofSize: 24)
        }
        btn.tintColor = .white
        return btn
    }()
    
    private let acceptButton: UIButton = {
        let btn = UIButton(type: .custom)
        btn.backgroundColor = .systemGreen
        btn.layer.cornerRadius = 37.5
        if #available(iOS 13.0, *) {
            btn.setImage(UIImage(systemName: "phone.fill"), for: .normal)
        } else {
            btn.setTitle("📞", for: .normal)
            btn.titleLabel?.font = .systemFont(ofSize: 24)
        }
        btn.tintColor = .white
        btn.isHidden = true
        return btn
    }()
    
    private var dialKeyboard: ActiveCallDialKeyboard?
    private var dialKeyboardBottomConstraint: NSLayoutConstraint?
    private var isKeyboardVisible = false
    private var isMuted = false
    private var isSpeakerOn = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .black
        
        setupUI()
        setupCallbacks()
        updateUI()
        
        // 启用距离传感器
        UIDevice.current.isProximityMonitoringEnabled = true
        
        // 不再启动超时检测：
        // 1. 错误响应（403/404等）会通过 sipCallDisconnect 通知携带错误码处理
        // 2. 如果用户不接电话，应该继续等待，不应该判定为失败
        // 3. 真正的网络超时（无任何响应）由底层框架处理
    }
    
    private var audioConfigTimer: Timer?
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        // 在页面显示后，主动检查并配置音频会话
            DispatchQueue.main.asyncAfter(deadline: .now() + UIConstants.Timing.medium) { [weak self] in
            self?.phoneService.ensureAudioSessionForCall()
        }
        
        // 记录通话开始时间，用于检测通话是否已建立
        let callStartTime = Date()
        
        // 设置一个定时器，每2秒检查一次，主动配置音频会话
        // 这是一个更主动的方案，确保音频最终能正确配置
        audioConfigTimer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: true) { [weak self] timer in
            guard let self = self else {
                timer.invalidate()
                return
            }
            
            // 如果通话已断开或失败，停止定时器
            if let status = self.call?.status, status == .disconnected || status == .failed {
                timer.invalidate()
                self.audioConfigTimer = nil
                return
            }
            
            // 计算通话持续时间
            let elapsed = Date().timeIntervalSince(callStartTime)
            
            // 如果通话状态是 calling 且已经超过5秒，说明可能已经接通但没有收到通知
            if let status = self.call?.status, status == .calling && elapsed > 5.0 {
                self.call?.status = .connected
                self.statusLabel.text = "00:00"
                if self.timer == nil {
                    self.startTimer()
                }
            }
            
            // 如果通话状态不是 disconnected 或 failed，就主动配置音频
            if let status = self.call?.status, status != .disconnected && status != .failed {
                self.phoneService.ensureAudioSessionForCall()
            } else if self.call?.status == nil {
                self.phoneService.ensureAudioSessionForCall()
            }
        }
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        // 页面消失时，停止定时器
        audioConfigTimer?.invalidate()
        audioConfigTimer = nil
    }
    
    private func setupUI() {
        view.addSubview(backgroundImageView)
        view.addSubview(nameLabel)
        view.addSubview(statusLabel)
        view.addSubview(muteButton)
        view.addSubview(speakerButton)
        view.addSubview(keyboardButton)
        view.addSubview(hangupButton)
        view.addSubview(acceptButton)
        
        backgroundImageView.translatesAutoresizingMaskIntoConstraints = false
        nameLabel.translatesAutoresizingMaskIntoConstraints = false
        statusLabel.translatesAutoresizingMaskIntoConstraints = false
        muteButton.translatesAutoresizingMaskIntoConstraints = false
        speakerButton.translatesAutoresizingMaskIntoConstraints = false
        keyboardButton.translatesAutoresizingMaskIntoConstraints = false
        hangupButton.translatesAutoresizingMaskIntoConstraints = false
        acceptButton.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            backgroundImageView.topAnchor.constraint(equalTo: view.topAnchor),
            backgroundImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            backgroundImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            backgroundImageView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            
            nameLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            nameLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: UIConstants.Layout.activeCallNameTopOffset),
            nameLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: UIConstants.Layout.horizontalPadding),
            nameLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -UIConstants.Layout.horizontalPadding),
            
            statusLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            statusLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: UIConstants.Layout.activeCallStatusSpacing),
            statusLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: UIConstants.Layout.horizontalPadding),
            statusLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -UIConstants.Layout.horizontalPadding),
            
            muteButton.widthAnchor.constraint(equalToConstant: 75),
            muteButton.heightAnchor.constraint(equalToConstant: 75),
            muteButton.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: -UIConstants.Layout.activeCallSideButtonOffset),
            muteButton.bottomAnchor.constraint(equalTo: hangupButton.topAnchor, constant: -UIConstants.Layout.activeCallMiddleButtonOffset),
            
            speakerButton.widthAnchor.constraint(equalToConstant: 75),
            speakerButton.heightAnchor.constraint(equalToConstant: 75),
            speakerButton.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: UIConstants.Layout.activeCallSideButtonOffset),
            speakerButton.centerYAnchor.constraint(equalTo: muteButton.centerYAnchor),
            
            keyboardButton.widthAnchor.constraint(equalToConstant: 75),
            keyboardButton.heightAnchor.constraint(equalToConstant: 75),
            keyboardButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            keyboardButton.centerYAnchor.constraint(equalTo: muteButton.centerYAnchor),
            
            hangupButton.widthAnchor.constraint(equalToConstant: 75),
            hangupButton.heightAnchor.constraint(equalToConstant: 75),
            hangupButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            hangupButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -UIConstants.Layout.activeCallBottomButtonOffset),
            
            acceptButton.widthAnchor.constraint(equalToConstant: 75),
            acceptButton.heightAnchor.constraint(equalToConstant: 75),
            acceptButton.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: -UIConstants.Layout.activeCallSideButtonOffset),
            acceptButton.centerYAnchor.constraint(equalTo: hangupButton.centerYAnchor)
        ])
        
        muteButton.addTarget(self, action: #selector(toggleMute), for: .touchUpInside)
        speakerButton.addTarget(self, action: #selector(toggleSpeaker), for: .touchUpInside)
        keyboardButton.addTarget(self, action: #selector(toggleKeyboard), for: .touchUpInside)
        hangupButton.addTarget(self, action: #selector(hangup), for: .touchUpInside)
        acceptButton.addTarget(self, action: #selector(accept), for: .touchUpInside)
    }
    
    private func setupCallbacks() {
        NotificationCenter.default.addObserver(
            forName: NSNotification.Name(NSNotification.Name.sipCallCalling.rawValue),
            object: nil,
            queue: .main
        ) { [weak self] _ in
            self?.statusLabel.text = "正在呼叫..."
            self?.call?.status = .calling
            // 不启动超时检测：
            // 1. 错误响应（403/404等）会通过 sipCallDisconnect 通知携带错误码处理
            // 2. 如果用户不接电话，应该继续等待，不应该判定为失败
            // 3. 真正的网络超时（无任何响应）由底层框架处理
        }
        
        NotificationCenter.default.addObserver(
            forName: NSNotification.Name(NSNotification.Name.sipCallConnecting.rawValue),
            object: nil,
            queue: .main
        ) { [weak self] _ in
            self?.statusLabel.text = "振铃中..."
            self?.call?.status = .connecting
            self?.stopCallFailureCheck()
            
            // 振铃时也确保音频会话正确配置
            DispatchQueue.main.asyncAfter(deadline: .now() + UIConstants.Timing.callEnsureAudioDelay) { [weak self] in
                self?.phoneService.ensureAudioSessionForCall()
            }
            
            // 备用方案：如果 sipCallConfirm 通知没有发送，在振铃后延迟3秒主动配置音频
            DispatchQueue.main.asyncAfter(deadline: .now() + UIConstants.Timing.callRingingEnsureDelay) { [weak self] in
                if let status = self?.call?.status, status == .connecting || status == .connected {
                    self?.phoneService.ensureAudioSessionForCall()
                    if status == .connecting {
                        self?.call?.status = .connected
                        self?.statusLabel.text = "00:00"
                        self?.startTimer()
                    }
                }
            }
            
            // 额外备用方案：在振铃后延迟5秒再次配置音频
            DispatchQueue.main.asyncAfter(deadline: .now() + UIConstants.Timing.callRingingEnsureExtraDelay) { [weak self] in
                if let status = self?.call?.status, status == .connecting || status == .connected {
                    self?.phoneService.ensureAudioSessionForCall()
                }
            }
        }
        
        NotificationCenter.default.addObserver(
            forName: NSNotification.Name(NSNotification.Name.sipCallConfirm.rawValue),
            object: nil,
            queue: .main
        ) { [weak self] _ in
            self?.statusLabel.text = "00:00"
            self?.call?.status = .connected
            self?.stopCallFailureCheck()
            self?.startTimer()
            
            // 通话接通后，确保音频会话正确配置并激活
            DispatchQueue.main.asyncAfter(deadline: .now() + UIConstants.Timing.short) { [weak self] in
                self?.phoneService.ensureAudioSessionForCall()
            }
        }
        
        NotificationCenter.default.addObserver(
            forName: NSNotification.Name(NSNotification.Name.sipCallDisconnect.rawValue),
            object: nil,
            queue: .main
        ) { [weak self] notification in
            // 防止重复处理：如果呼叫已经断开，忽略后续通知
            guard let self = self else { return }
            if self.call?.status == .disconnected || self.call?.status == .failed {
                return
            }
            
            self.stopCallFailureCheck()
            
            // 检查是否有错误信息
            var errorMessage: String? = nil
            var errorCode: Int? = nil
            var isCallFailed = false
            var hangupType: String? = nil
            
            if let userInfo = notification.userInfo {
                if let reasonDescription = userInfo[kSIPReasonDescriptionKey] as? String {
                    errorMessage = reasonDescription
                }
                if let reasonCode = userInfo[kSIPReasonKey] as? Int {
                    errorCode = reasonCode
                    if reasonCode >= 400 {
                        isCallFailed = true
                    }
                }
                // 读取挂断类型：主叫挂断/被叫挂断
                if let hangupTypeValue = userInfo[kSIPHangupTypeKey] as? String {
                    hangupType = hangupTypeValue
                    // 判断是主叫挂断还是被叫挂断
                    let isCallerHangup = hangupTypeValue.contains("主叫") || hangupTypeValue.lowercased().contains("caller")
                    let isCalleeHangup = hangupTypeValue.contains("被叫") || hangupTypeValue.lowercased().contains("callee")
                    
                    if isCallerHangup {
                        AppLogger.info("主叫挂断", category: "ActiveCall")
                    } else if isCalleeHangup {
                        AppLogger.info("被叫挂断", category: "ActiveCall")
                    } else {
                        AppLogger.info("挂断类型: \(hangupTypeValue)", category: "ActiveCall")
                    }
                }
            }
            
            // 主要依赖错误码来判断失败
            // 如果错误码 >= 400，说明是服务器返回的错误响应（如403/404等），应该判定为失败
            // 如果没有错误码，说明是正常挂断（用户主动挂断或对方挂断），不应该判定为失败
            if isCallFailed {
                // 有错误码，判定为呼叫失败
                self.handleCallFailure(reason: errorMessage, code: errorCode)
            } else {
                // 正常挂断
                self.call?.status = .disconnected
                self.statusLabel.text = "通话已结束"
                self.call?.endTime = Date()
                if let startTime = self.call?.startTime, let endTime = self.call?.endTime {
                    self.call?.duration = endTime.timeIntervalSince(startTime)
                }
                self.stopTimer()
                
                // 延迟关闭页面
                DispatchQueue.main.asyncAfter(deadline: .now() + UIConstants.Timing.medium) {
                    if let navigationController = self.navigationController,
                       navigationController.viewControllers.count > 1 {
                        navigationController.popViewController(animated: true)
                    } else {
                        self.dismiss(animated: true, completion: nil)
                    }
                }
            }
        }
    }
    
    private func updateUI() {
        nameLabel.text = call?.displayNameOrNumber ?? "未知号码"
    }
    
    private func startTimer() {
        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
            self?.updateTimer()
        }
    }
    
    private func stopTimer() {
        timer?.invalidate()
        timer = nil
    }
    
    private func updateTimer() {
        callDuration += 1
        let hours = Int(callDuration) / 3600
        let minutes = (Int(callDuration) % 3600) / 60
        let seconds = Int(callDuration) % 60
        
        if hours > 0 {
            statusLabel.text = String(format: "%02d:%02d:%02d", hours, minutes, seconds)
        } else {
            statusLabel.text = String(format: "%02d:%02d", minutes, seconds)
        }
    }
    
    @objc private func toggleMute() {
        isMuted.toggle()
        AppLogger.debug("静音按钮点击: isMuted = \(isMuted)", category: "ActiveCall")
        phoneService.setMute(isMuted)
        muteButton.isSelected = isMuted
        muteButton.backgroundColor = isMuted ? .systemGreen : UIColor(hexString: "#2C2C2E")
    }
    
    @objc private func toggleSpeaker() {
        isSpeakerOn.toggle()
        phoneService.setLoudSpeaker(isSpeakerOn)
        speakerButton.isSelected = isSpeakerOn
        speakerButton.backgroundColor = isSpeakerOn ? .systemGreen : UIColor(hexString: "#2C2C2E")
    }
    
    @objc private func toggleKeyboard() {
        isKeyboardVisible.toggle()
        
        if isKeyboardVisible {
            showDialKeyboard()
        } else {
            hideDialKeyboard()
        }
    }
    
    private func showDialKeyboard() {
        if dialKeyboard == nil {
            dialKeyboard = ActiveCallDialKeyboard()
            dialKeyboard?.delegate = self
            dialKeyboard?.alpha = 0
            dialKeyboard?.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(dialKeyboard!)
            
            // 使用 Auto Layout 布局键盘
            // 通过 centerYAnchor 定位，初始位置在屏幕外（下方）
            dialKeyboardBottomConstraint = dialKeyboard?.centerYAnchor.constraint(
                equalTo: view.centerYAnchor,
                constant: 1000 // 初始位置在屏幕外（下方）
            )
            
            NSLayoutConstraint.activate([
                dialKeyboard!.leadingAnchor.constraint(equalTo: view.leadingAnchor),
                dialKeyboard!.trailingAnchor.constraint(equalTo: view.trailingAnchor),
                dialKeyboard!.heightAnchor.constraint(equalToConstant: 320), // 4行按钮的高度
                dialKeyboardBottomConstraint!
            ])
            
            // 强制布局更新
            view.layoutIfNeeded()
        }
        
        // 更新约束，将键盘移到 statusLabel 和 muteButton 之间的中间位置
        // 键盘的 centerYAnchor 位于 view 的中心位置
        dialKeyboardBottomConstraint?.constant = -40
        
        UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.5, options: .curveEaseOut) {
            self.view.layoutIfNeeded()
            self.dialKeyboard?.alpha = 1
            // 键盘显示时，稍微降低上方内容的透明度
            self.nameLabel.alpha = 0.6
            self.statusLabel.alpha = 0.6
        }
        keyboardButton.isSelected = true
    }
    
    private func hideDialKeyboard() {
        // 将键盘移回屏幕外
        dialKeyboardBottomConstraint?.constant = 1000
        
        UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseIn) {
            self.view.layoutIfNeeded()
            self.dialKeyboard?.alpha = 0
            self.nameLabel.alpha = 1.0
            self.statusLabel.alpha = 1.0
        }
        keyboardButton.isSelected = false
    }
    
    @objc private func accept() {
        phoneService.acceptCall()
        acceptButton.isHidden = true
    }
    
    @objc private func hangup() {
        // 检查呼叫状态，如果已经断开或失败，不需要再次挂断
        if let status = call?.status, status == .disconnected || status == .failed {
            if let navigationController = navigationController,
               navigationController.viewControllers.count > 1 {
                navigationController.popViewController(animated: true)
            } else {
                dismiss(animated: true, completion: nil)
            }
            return
        }
        
        phoneService.hangupCall()
        
        // 如果挂断后没有收到通知，手动关闭页面（作为备用方案）
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in
            if self?.call?.status != .disconnected && self?.call?.status != .failed {
                if let navigationController = self?.navigationController,
                   navigationController.viewControllers.count > 1 {
                    navigationController.popViewController(animated: true)
                } else {
                    self?.dismiss(animated: true, completion: nil)
                }
            }
        }
    }
    
    private func showErrorAlert(message: String) {
        let alert = UIAlertController(title: "呼叫失败", message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: L.General.ok, style: .default))
        present(alert, animated: true)
    }
    
    private func startCallFailureCheck() {
        // 不再使用超时检测来判定呼叫失败
        // 
        // 原因：
        // 1. 错误响应（403/404等）会通过 sipCallDisconnect 通知携带错误码处理
        //    - 底层框架收到错误响应后会发送 sipCallDisconnect 通知，并携带错误码
        //    - 我们在 sipCallDisconnect 通知处理中检查错误码 >= 400 来判定失败
        // 
        // 2. 如果用户不接电话，应该继续等待，不应该判定为失败
        //    - 用户可能正在考虑是否接听
        //    - 振铃状态（180 Ringing）是正常的，即使通知延迟也不应该判定为失败
        // 
        // 3. 真正的网络超时（无任何响应）由底层框架处理
        //    - 底层框架会检测网络超时并发送 sipCallDisconnect 通知
        //    - 我们依赖底层框架的通知机制，而不是自己实现超时检测
        //
        // 保留此方法是为了兼容性，但不再启动定时器
        stopCallFailureCheck()
    }
    
    private func stopCallFailureCheck() {
        callFailureCheckTimer?.invalidate()
        callFailureCheckTimer = nil
    }
    
    private func handleCallFailure(reason: String?, code: Int?) {
        call?.status = .failed
        call?.endTime = Date()
        if let startTime = call?.startTime, let endTime = call?.endTime {
            call?.duration = endTime.timeIntervalSince(startTime)
        }
        
        let displayMessage = ErrorMessageProvider.callErrorMessage(code: code, underlyingMessage: reason)
        
        statusLabel.text = displayMessage
        stopTimer()
        stopCallFailureCheck()
        
        // 显示错误提示
        DispatchQueue.main.asyncAfter(deadline: .now() + UIConstants.Timing.short) {
            self.showErrorAlert(message: displayMessage)
        }
        
        // 延迟关闭页面
        DispatchQueue.main.asyncAfter(deadline: .now() + UIConstants.Timing.long) {
            if let navigationController = self.navigationController,
               navigationController.viewControllers.count > 1 {
                navigationController.popViewController(animated: true)
            } else {
                self.dismiss(animated: true, completion: nil)
            }
        }
    }
    
    deinit {
        UIDevice.current.isProximityMonitoringEnabled = false
        stopTimer()
        stopCallFailureCheck()
        NotificationCenter.default.removeObserver(self)
    }
}

extension ActiveCallViewController: ActiveCallDialKeyboardDelegate {
    func activeCallDialKeyboardDidInputNumber(_ number: String) {
        phoneService.sendDTMF(number: number)
    }
}

