//
//  VideoEditorVC.swift
//  WoWonder
//
//  Created by iMac on 19/05/25.
//  Copyright © 2025 ScriptSun. All rights reserved.
//

import UIKit
import AVFoundation
import AVKit
import Async
import Toast_Swift
import ionicons

protocol VideoEditorVCDelegate {
    func videoEditorDidSaveVideo(url: URL)
}

class VideoEditorVC: BaseVC {
    
    // MARK: - IBOutlets
    
    @IBOutlet weak var videoView: UIView!
    @IBOutlet weak var audioIconImageView: UIImageView!
    @IBOutlet weak var videoTrimmer: VideoTrimmer!
    @IBOutlet weak var emojiButton: UIButton!
    @IBOutlet weak var captionTextView: EmojiTextView!
    @IBOutlet weak var leadingTrimLabel: UILabel!
    @IBOutlet weak var trailingTrimLabel: UILabel!
    @IBOutlet weak var trimDurationLabel: UILabel!
    @IBOutlet weak var playButton: UIButton!
    
    // MARK: - Properties
    
    var videoUrl: URL? = nil
    let playerController = AVPlayerViewController()
    private var wasPlaying = false
    private var player: AVPlayer! {playerController.player}
    private var asset: AVAsset!
    var removeAudio = false
    var isStory = false
    var delegate: VideoEditorVCDelegate?
    
    private func updateLabels() {
        leadingTrimLabel.text = videoTrimmer.selectedRange.start.displayString
        trailingTrimLabel.text = videoTrimmer.selectedRange.end.displayString
        trimDurationLabel.text = videoTrimmer.selectedRange.duration.displayString
    }
    
    private func updatePlayerAsset() {
        let outputRange = videoTrimmer.trimmingState == .none ? videoTrimmer.selectedRange : asset.fullRange
        let trimmedAsset = asset.trimmedComposition(outputRange)
        if trimmedAsset != player.currentItem?.asset {
            player.replaceCurrentItem(with: AVPlayerItem(asset: trimmedAsset))
        }
    }
    
    // MARK: - View Life Cycles
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view.
        
        self.initialConfig()
    }
    
    // MARK: - Selectors
    
    // Back Button Action
    @IBAction func backButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        self.navigationController?.popViewController(animated: true)
    }
    
    // Emoji Button Action
    @IBAction func emojiButtonAction(_ sender: UIButton) {
        self.captionTextView.isEmojiKeyboard = true
        self.captionTextView.becomeFirstResponder()
    }
    
    // Send Button Action
    @IBAction func sendButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        let start = videoTrimmer.selectedRange.start
        let end = videoTrimmer.selectedRange.end
        let startTimeMs = Int64(CMTimeGetSeconds(start) * 1000)
        let endTimeMs = Int64(CMTimeGetSeconds(end) * 1000)
        VideoManager.shared.loadVideo(asset: self.asset)
        VideoManager.shared.trimVideo(startTimeMs: startTimeMs, endTimeMs: endTimeMs, includeAudio: !self.removeAudio) { result in
            Async.main {
                switch result {
                case .success(let success):
                    print("success >>>>> ", success)
                    let videoUrl = URL(fileURLWithPath: success)
                    if self.isStory {
                        do {
                            let videoData = try Data(contentsOf: videoUrl)
                            self.createStory(data: videoData, type: "video")
                        } catch {
                            print(error.localizedDescription)
                        }
                    } else {
                        self.delegate?.videoEditorDidSaveVideo(url: videoUrl)
                        self.navigationController?.popViewController(animated: true)
                    }
                case .failure(let failure):
                    print("error >>>>> ", failure.localizedDescription)
                }
            }
        }
        VideoManager.shared.clearCache()
    }
    
    // Audio Button Action
    @IBAction func audioButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        if let newVC = R.storyboard.popup.replaceAudioAlertVC() {
            newVC.delegate = self
            newVC.modalPresentationStyle = .overCurrentContext
            newVC.modalTransitionStyle = .crossDissolve
            self.present(newVC, animated: true)
        }
    }
    
    // Play Button Action
    @IBAction func playButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        if player.isPlaying {
            player.pause()
        } else {
            player.play()
        }
        self.playButton.setImage(player.icon, for: .normal)
    }
    
    @objc private func didBeginTrimming(_ sender: VideoTrimmer) {
        updateLabels()

        wasPlaying = (player.timeControlStatus != .paused)
        player.pause()

        updatePlayerAsset()
    }

    @objc private func didEndTrimming(_ sender: VideoTrimmer) {
        updateLabels()

        if wasPlaying == true {
            player.play()
        }

        updatePlayerAsset()
    }

    @objc private func selectedRangeDidChanged(_ sender: VideoTrimmer) {
        updateLabels()
    }

    @objc private func didBeginScrubbing(_ sender: VideoTrimmer) {
        updateLabels()

        wasPlaying = (player.timeControlStatus != .paused)
        player.pause()
    }

    @objc private func didEndScrubbing(_ sender: VideoTrimmer) {
        updateLabels()

        if wasPlaying == true {
            player.play()
        }
    }

    @objc private func progressDidChanged(_ sender: VideoTrimmer) {
        updateLabels()

        let time = CMTimeSubtract(videoTrimmer.progress, videoTrimmer.selectedRange.start)
        player.seek(to: time, toleranceBefore: .zero, toleranceAfter: .zero)
    }
    
    // MARK: - Helper Functions
    
    // Initial Config
    func initialConfig() {
        self.setupUI()
        self.setUpCaptionTextView()
    }
    
    // SetUp Caption TextView
    func setUpCaptionTextView() {
        self.captionTextView.delegate = self
        self.captionTextView.addPlaceholder("Add a caption...", with: .text_color)
    }
    
    // Setup UI
    func setupUI() {
        if self.isStory {
            self.emojiButton.isHidden = false
            self.captionTextView.isHidden = false
        } else {
            self.emojiButton.isHidden = true
            self.captionTextView.isHidden = true
        }
        self.audioIconImageView.image = IonIcons.image(withIcon: self.removeAudio ? "\u{f3a2}" : "\u{f123}", size: 20, color: .white)
        if let videoUrl = self.videoUrl {
            asset = AVURLAsset(url: videoUrl, options: [AVURLAssetPreferPreciseDurationAndTimingKey: true])
            self.setupPlayerController()
            videoTrimmer.minimumDuration = CMTime(seconds: 1, preferredTimescale: 600)
            videoTrimmer.addTarget(self, action: #selector(didBeginTrimming(_:)), for: VideoTrimmer.didBeginTrimming)
            videoTrimmer.addTarget(self, action: #selector(didEndTrimming(_:)), for: VideoTrimmer.didEndTrimming)
            videoTrimmer.addTarget(self, action: #selector(selectedRangeDidChanged(_:)), for: VideoTrimmer.selectedRangeChanged)
            videoTrimmer.addTarget(self, action: #selector(didBeginScrubbing(_:)), for: VideoTrimmer.didBeginScrubbing)
            videoTrimmer.addTarget(self, action: #selector(didEndScrubbing(_:)), for: VideoTrimmer.didEndScrubbing)
            videoTrimmer.addTarget(self, action: #selector(progressDidChanged(_:)), for: VideoTrimmer.progressChanged)
            videoTrimmer.asset = asset
            updatePlayerAsset()
            player.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 30), queue: .main) { [weak self] time in
                guard let self = self else {return}
                // when we're not trimming, the players starting point is actual later than the trimmer,
                // (because the vidoe has been trimmed), so we need to account for that.
                // When we're trimming, we always show the full video
                let finalTime = self.videoTrimmer.trimmingState == .none ? CMTimeAdd(time, self.videoTrimmer.selectedRange.start) : time
                self.videoTrimmer.progress = finalTime
            }
            updateLabels()
        }
    }
    
    func setupPlayerController() {
        playerController.player = AVPlayer()
        // playerController.view.backgroundColor = .clear
        self.addChild(playerController)
        self.videoView.addSubview(playerController.view)
        playerController.view.frame = self.videoView.bounds
        playerController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        playerController.didMove(toParent: self)
        playerController.showsPlaybackControls = false
    }
    
}

// MARK: - Extensions

// MARK: Api Call
extension VideoEditorVC {
    
    private func createStory(data: Data, type: String) {
        self.showProgressDialog(text: NSLocalizedString("Loading...", comment: "Loading..."))
        let sessionToken = AppInstance.instance.sessionId ?? ""
        let storyText = self.captionTextView.text ?? ""
        Async.background {
            StoriesManager.instance.createStory(session_Token: sessionToken, type: type, storyDescription: storyText, storyTitle: "", data: data, completionBlock: { (success, sessionError, serverError, error) in
                Async.main {
                    self.dismissProgressDialog {
                        if success != nil {
                            print("userList = \(success?.apiStatus ?? 0)")
                            self.navigationController?.popToRootViewController(animated: true)
                        } else if sessionError != nil {
                            self.view.makeToast(sessionError?.errors?.error_text)
                            print("sessionError = \(sessionError?.errors?.error_text ?? "")")
                        } else if serverError != nil {
                            self.view.makeToast(serverError?.errors?.error_text)
                            print("serverError = \(serverError?.errors?.error_text ?? "")")
                        } else {
                            self.view.makeToast(error?.localizedDescription)
                            print("error = \(error?.localizedDescription ?? "")")
                        }
                    }
                }
            })
        }
    }
    
}

// MARK: UITextViewDelegate Methods
extension VideoEditorVC: UITextViewDelegate {
    
    func textViewDidEndEditing(_ textView: UITextView) {
        self.captionTextView.isEmojiKeyboard = false
    }
    
}

// MARK: ReplaceAudioAlertVCDelegate
extension VideoEditorVC: ReplaceAudioAlertVCDelegate {
    
    func handleReplaceAudioOptionTap(replace_audio: String) {
        switch replace_audio {
        case "No":
            self.removeAudio = false
        case "Remove":
            self.removeAudio = true
        case "Choose source":
            self.removeAudio = false
        default:
            break
        }
        self.audioIconImageView.image = IonIcons.image(withIcon: self.removeAudio ? "\u{f3a2}" : "\u{f123}", size: 20, color: .white)
    }
    
}

extension CMTime {
    
    var displayString: String {
        let offset = TimeInterval(seconds)
        let formatter = DateComponentsFormatter()
        formatter.unitsStyle = .positional
        formatter.zeroFormattingBehavior = .pad
        formatter.allowedUnits = [.minute, .second]
        return formatter.string(from: offset) ?? "00:00"
    }
    
}

extension AVAsset {
    
    var fullRange: CMTimeRange {
        return CMTimeRange(start: .zero, duration: duration)
    }
    
    func trimmedComposition(_ range: CMTimeRange) -> AVAsset {
        guard CMTimeRangeEqual(fullRange, range) == false else { return self }

        let composition = AVMutableComposition()
        try? composition.insertTimeRange(range, of: self, at: .zero)

        if let videoTrack = tracks(withMediaType: .video).first {
            composition.tracks.forEach {$0.preferredTransform = videoTrack.preferredTransform}
        }
        return composition
    }
    
}
