//  GalleryViewController.swift
//  Tusker
//
//  Created by Shadowfacts on 6/13/19.
//  Copyright © 2019 Shadowfacts. All rights reserved.
//

import UIKit
import Pachyderm
import AVFoundation
import AVKit

class GalleryViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, LargeImageAnimatableViewController {

    weak var avPlayerViewControllerDelegate: AVPlayerViewControllerDelegate?
    
    let attachments: [Attachment]
    let sourceViews: WeakArray<UIImageView>
    let startIndex: Int
    
    var pages: [UIViewController]!
    
    var currentIndex: Int {
        guard let vc = viewControllers?.first,
            let index = pages.firstIndex(of: vc) else {
                fatalError()
        }
        return index
    }

    var animationSourceView: UIImageView? { sourceViews[currentIndex] }
    var largeImageController: LargeImageViewController? {
        // use protocol because page controllers may be loading or non-loading VCs
        (pages[currentIndex] as? LargeImageAnimatableViewController)?.largeImageController
    }
    var animationImage: UIImage? {
        if let page = pages[currentIndex] as? LargeImageAnimatableViewController,
            let image = page.animationImage {
            return image
        } else {
            return animationSourceView?.image
        }
    }
    var dismissInteractionController: LargeImageInteractionController?
    
    var isInteractivelyAnimatingDismissal: Bool = false {
        didSet {
            setNeedsStatusBarAppearanceUpdate()
        }
    }
    
    override var prefersStatusBarHidden: Bool {
        return !isInteractivelyAnimatingDismissal
    }
    override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
        return .none
    }
    override var childForHomeIndicatorAutoHidden: UIViewController? {
        return viewControllers?.first
    }
    
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if UIDevice.current.userInterfaceIdiom == .phone {
            return .allButUpsideDown
        } else {
            return .all
        }
    }
    
    init(attachments: [Attachment], sourceViews: [UIImageView?], startIndex: Int) {
        self.attachments = attachments
        self.sourceViews = WeakArray(sourceViews)
        self.startIndex = startIndex
        
        super.init(transitionStyle: .scroll, navigationOrientation: .horizontal)
        
        modalPresentationStyle = .fullScreen
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.pages = attachments.enumerated().map { (index, attachment) in
            switch attachment.kind {
            case .image:
                let vc = LoadingLargeImageViewController(attachment: attachment)
                vc.shrinkGestureEnabled = false
                vc.animationSourceView = sourceViews[index]
                return vc
            case .video, .audio:
                let vc = GalleryPlayerViewController()
                vc.playerVC.player = AVPlayer(url: attachment.url)
                vc.playerVC.delegate = avPlayerViewControllerDelegate
                vc.attachment = attachment
                return vc
            case .gifv:
                // Passing the source view to the LargeImageGifvContentView is a crappy workaround for not
                // having the current frame to use as the animationImage. This will break when there
                // are more than 4 attachments and there is a gifv at index >= 3 (the More... button will show
                // in place of the fourth attachment, so there aren't source views for the attachments at index >= 3).
                // This isn't a priority as only Mastodon converts gifs to gifvs, and Mastodon (in its default configuration,
                // I don't know about forks) doesn't allow more than four attachments, meaning there will always be a source view.
                let gifvContentView = LargeImageGifvContentView(attachment: attachment, source: sourceViews[index]!)
                let vc = LargeImageViewController(contentView: gifvContentView, description: attachment.description, sourceView: nil)
                vc.shrinkGestureEnabled = false
                return vc
            default:
                return UINavigationController(rootViewController: GalleryFallbackViewController(attachment: attachment))
            }
        }
        
        setViewControllers([pages[startIndex]], direction: .forward, animated: false)

        self.dataSource = self
        self.delegate = self
        
        overrideUserInterfaceStyle = .dark

        dismissInteractionController = LargeImageInteractionController(viewController: self)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        if let vc = pages[currentIndex] as? AVPlayerViewController {
            // when the gallery is first shown, after the transition finishes, the controls for the player controller appear semi-transparent
            // hiding the controls and then immediately reshowing them makes sure they're visible when the gallery is presented
            vc.showsPlaybackControls = false
            vc.showsPlaybackControls = true

            // begin playing the video as soon as we appear
            vc.player?.play()
        }
    }
    
    override func accessibilityPerformEscape() -> Bool {
        dismiss(animated: true)
        return true
    }

    // MARK: - Page View Controller Data Source
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        guard let index = pages.firstIndex(of: viewController),
            index > 0 else {
            return nil
        }
        return pages[index - 1]
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        guard let index = pages.firstIndex(of: viewController),
            index < pages.count - 1 else {
                return nil
        }
        return pages[index + 1]
    }
    
    // MARK: - Page View Controller Delegate
    func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
        if let pending = pendingViewControllers.first as? LoadingLargeImageViewController,
            let current = viewControllers!.first as? LoadingLargeImageViewController {
            pending.controlsVisible = current.controlsVisible
        }
        
        if let pending = pendingViewControllers.first as? AVPlayerViewController {
            // show controls and begin playing when the player page becomes visible
            pending.showsPlaybackControls = true
            pending.player?.play()
        }
    }

}
