//
//  Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//

import Foundation

private class CallKitExperienceUpgradeViewController: ExperienceUpgradeViewController {

    override func loadView() {
        super.loadView()
        assert(view != nil)
        assert(bodyLabel != nil)

        // Privacy Settings Button
        let privacySettingsButton = UIButton()
        view.addSubview(privacySettingsButton)
        let privacyTitle = NSLocalizedString("UPGRADE_EXPERIENCE_CALLKIT_PRIVACY_SETTINGS_BUTTON", comment: "button label shown once when when user upgrades app, in context of call kit")
        privacySettingsButton.setTitle(privacyTitle, for: .normal)
        privacySettingsButton.setTitleColor(UIColor.ows_signalBrandBlue(), for: .normal)
        privacySettingsButton.isUserInteractionEnabled = true
        privacySettingsButton.addTarget(self, action:#selector(didTapPrivacySettingsButton), for: .touchUpInside)
        privacySettingsButton.titleLabel?.font = bodyLabel.font

        // Privacy Settings Button layout
        privacySettingsButton.autoPinWidthToSuperview(withMargin: bodyMargin)
        privacySettingsButton.autoPinEdge(.top, to: .bottom, of: bodyLabel, withOffset: ScaleFromIPhone5(12))
        privacySettingsButton.sizeToFit()
    }

    // MARK: - Actions

    func didTapPrivacySettingsButton(sender: UIButton) {
        Logger.debug("\(TAG) in \(#function)")

        // dismiss the modally presented view controller, then proceed.
        experienceUpgradesPageViewController.dismiss(animated: true) {
            let fromViewController = UIApplication.shared.frontmostViewController
            assert(fromViewController != nil)

            // Construct the "settings" view & push the "privacy settings" view.
            let navigationController = UIStoryboard.main.instantiateViewController(withIdentifier:"SettingsNavigationController") as! UINavigationController
            assert(navigationController.viewControllers.count == 1)

            let privacySettingsViewController = PrivacySettingsTableViewController()
            navigationController.pushViewController(privacySettingsViewController, animated:false)
            
            fromViewController?.present(navigationController, animated: true, completion: nil)
        }
    }
}

private class ExperienceUpgradeViewController: UIViewController {
    let TAG = "[ExperienceUpgradeViewController]"

    let header: String
    let body: String
    let image: UIImage?
    let experienceUpgradesPageViewController: ExperienceUpgradesPageViewController

    var bodyLabel: UILabel!
    let bodyMargin = ScaleFromIPhone5To7Plus(12, 24)

    init(experienceUpgrade: ExperienceUpgrade, experienceUpgradesPageViewController: ExperienceUpgradesPageViewController) {
        header = experienceUpgrade.title
        body = experienceUpgrade.body
        image = experienceUpgrade.image
        self.experienceUpgradesPageViewController = experienceUpgradesPageViewController
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func loadView() {
        self.view = UIView()

        /// Create Views

        // Title label
        let titleLabel = UILabel()
        view.addSubview(titleLabel)
        titleLabel.text = header
        titleLabel.textAlignment = .center
        titleLabel.font = UIFont.ows_regularFont(withSize: ScaleFromIPhone5To7Plus(26, 32))
        titleLabel.textColor = UIColor.white
        titleLabel.minimumScaleFactor = 0.5
        titleLabel.adjustsFontSizeToFitWidth = true;

        // Body label
        let bodyLabel = UILabel()
        self.bodyLabel = bodyLabel
        view.addSubview(bodyLabel)
        bodyLabel.text = body
        bodyLabel.font = UIFont.ows_lightFont(withSize: ScaleFromIPhone5To7Plus(17, 22))
        bodyLabel.textColor = UIColor.black
        bodyLabel.numberOfLines = 0
        bodyLabel.lineBreakMode = .byWordWrapping
        bodyLabel.textAlignment = .center

        // Image
        let imageView = UIImageView(image: image)
        view.addSubview(imageView)
        imageView.contentMode = .scaleAspectFit

        /// Layout Views

        // Title label layout
        titleLabel.autoPinWidthToSuperview(withMargin: ScaleFromIPhone5To7Plus(16, 24))
        titleLabel.autoPinEdge(toSuperviewEdge: .top)

        // Body label layout
        bodyLabel.autoPinWidthToSuperview(withMargin: bodyMargin)
        bodyLabel.sizeToFit()

        // Image layout
        imageView.autoPinWidthToSuperview()
        imageView.autoSetDimension(.height, toSize: ScaleFromIPhone5To7Plus(200, 280))
        imageView.autoPinEdge(.top, to: .bottom, of: titleLabel, withOffset: ScaleFromIPhone5To7Plus(24, 32))
        imageView.autoPinEdge(.bottom, to: .top, of: bodyLabel, withOffset: -ScaleFromIPhone5To7Plus(18, 28))
    }
}

func setPageControlAppearance() {
    if #available(iOS 9.0, *) {
        let pageControl = UIPageControl.appearance(whenContainedInInstancesOf: [UIPageViewController.self])
        pageControl.pageIndicatorTintColor = UIColor.lightGray
        pageControl.currentPageIndicatorTintColor = UIColor.white
    } else {
        // iOS8 won't see the page controls =(
    }
}

class ExperienceUpgradesPageViewController: UIViewController, UIPageViewControllerDataSource {

    let TAG = "[ExperienceUpgradeViewController]"

    private let experienceUpgrades: [ExperienceUpgrade]
    private var allViewControllers = [UIViewController]()
    private var viewControllerIndexes = [UIViewController: Int]()

    let pageViewController: UIPageViewController

    // MARK: - Initializers

    required init(experienceUpgrades: [ExperienceUpgrade]) {
        self.experienceUpgrades = experienceUpgrades

        setPageControlAppearance()
        self.pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation:.horizontal, options: nil)
        super.init(nibName: nil, bundle: nil)
        self.pageViewController.dataSource = self

        experienceUpgrades.forEach { addViewController(experienceUpgrade: $0) }
    }

    @available(*, unavailable, message:"unavailable, use initWithExperienceUpgrade instead")
    required init?(coder aDecoder: NSCoder) {
        assert(false)
        // This should never happen, but so as not to explode we give some bogus data
        self.experienceUpgrades = [ExperienceUpgrade()]
        self.pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation:.horizontal, options: nil)
        super.init(coder: aDecoder)
        self.pageViewController.dataSource = self
    }

    // MARK: - View lifecycle

    override func viewDidLoad() {
        guard let firstViewController = allViewControllers.first else {
            Logger.error("\(TAG) no pages to show.")
            assertionFailure()
            dismiss(animated: true)
            return
        }

        addDismissGesture()
        self.pageViewController.setViewControllers([ firstViewController ], direction: .forward, animated: false, completion: nil)
    }

    override func loadView() {
        self.view = UIView()
        view.backgroundColor = UIColor.white

        //// Create Views

        // Header Background
        let headerBackgroundView = UIView()
        view.addSubview(headerBackgroundView)
        headerBackgroundView.backgroundColor = UIColor.ows_materialBlue()

        // Footer Background

        let footerBackgroundView = UIView()
        view.addSubview(footerBackgroundView)
        footerBackgroundView.backgroundColor = UIColor.ows_materialBlue()

        // Dismiss button
        let dismissButton = UIButton()
        view.addSubview(dismissButton)
        dismissButton.setTitle(NSLocalizedString("DISMISS_BUTTON_TEXT", comment: ""), for: .normal)
        dismissButton.setTitleColor(UIColor.white, for: .normal)
        dismissButton.isUserInteractionEnabled = true
        dismissButton.addTarget(self, action:#selector(didTapDismissButton), for: .touchUpInside)
        dismissButton.titleLabel?.font = UIFont.ows_mediumFont(withSize: ScaleFromIPhone5(20))
        let dismissInsetValue: CGFloat = ScaleFromIPhone5(10)
        dismissButton.contentEdgeInsets = UIEdgeInsets(top: dismissInsetValue, left: dismissInsetValue, bottom: dismissInsetValue, right: dismissInsetValue)

        guard let carouselView = self.pageViewController.view else {
            Logger.error("\(TAG) carousel view was unexpectedly nil")
            return
        }

        self.view.addSubview(carouselView)

        //// Layout Views

        // Header Background layout
        headerBackgroundView.autoPinWidthToSuperview()
        headerBackgroundView.autoPinEdge(toSuperviewEdge: .top)
        headerBackgroundView.autoSetDimension(.height, toSize: ScaleFromIPhone5(80))

        // Footer Background layout
        footerBackgroundView.autoPinWidthToSuperview()
        footerBackgroundView.autoPinEdge(toSuperviewEdge: .bottom)
        footerBackgroundView.autoSetDimension(.height, toSize: ScaleFromIPhone5(95))

        // Dismiss button layout
        dismissButton.autoHCenterInSuperview()
        dismissButton.autoPinEdge(toSuperviewEdge: .bottom, withInset: ScaleFromIPhone5(10))

        // Carousel View layout
        carouselView.autoPinWidthToSuperview()
        // negative inset so as to overlay the header text in the carousel view with the header background which
        // lives outside of the carousel. We do this so that the user can't bounce past the page view controllers
        // width limits, exposing the edge of the header.
        carouselView.autoPinEdge(.top, to: .bottom, of: headerBackgroundView, withOffset: ScaleFromIPhone5(-35))
        carouselView.autoPinEdge(.bottom, to: .top, of: dismissButton, withOffset: ScaleFromIPhone5(-10))
    }

    private func addDismissGesture() {
        let swipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleDismissGesture))
        swipeGesture.direction = .down
        view.addGestureRecognizer(swipeGesture)
    }

    // MARK: - UIPageViewControllerDataSource

    public func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        Logger.debug("\(TAG) in \(#function)")
        guard let currentIndex = self.viewControllerIndexes[viewController] else {
            assertionFailure()
            Logger.error("\(TAG) unknown view controller: \(viewController)")
            return nil
        }

        if currentIndex + 1 == allViewControllers.count {
            // already at last view controller
            return nil
        }

        return allViewControllers[currentIndex + 1]
    }

    public func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        Logger.debug("\(TAG) in \(#function)")
        guard let currentIndex = self.viewControllerIndexes[viewController] else {
            assertionFailure()
            Logger.error("\(TAG) unknown view controller: \(viewController)")
            return nil
        }

        if currentIndex <= 0 {
            // already at first view controller
            return nil
        }

        return allViewControllers[currentIndex - 1]
    }

    public func presentationCount(for pageViewController: UIPageViewController) -> Int {
        // don't show a page indicator if there's only one page.
        return allViewControllers.count == 1 ? 0 : allViewControllers.count
    }

    public func presentationIndex(for pageViewController: UIPageViewController) -> Int {
        guard let currentViewController = pageViewController.viewControllers?.first else {
            Logger.error("\(TAG) unexpectedly empty view controllers.")
            return 0
        }

        guard let currentIndex = self.viewControllerIndexes[currentViewController] else {
            Logger.error("\(TAG) unknown view controller: \(currentViewController)")
            return 0
        }

        return currentIndex
    }

    public func addViewController(experienceUpgrade: ExperienceUpgrade) {
        guard let identifier = ExperienceUpgradeId(rawValue: experienceUpgrade.uniqueId) else {
            Logger.error("\(TAG) unknown experience upgrade. skipping")
            assertionFailure()
            return
        }

        let viewController: ExperienceUpgradeViewController = {
            switch identifier {
            case .callKit:
                return CallKitExperienceUpgradeViewController(experienceUpgrade: experienceUpgrade, experienceUpgradesPageViewController: self)
            default:
                return ExperienceUpgradeViewController(experienceUpgrade: experienceUpgrade, experienceUpgradesPageViewController: self)
            }
        }()

        let count = allViewControllers.count
        viewControllerIndexes[viewController] = count
        allViewControllers.append(viewController)
    }

    func didTapDismissButton(sender: UIButton) {
        Logger.debug("\(TAG) in \(#function)")
        self.dismiss(animated: true)
    }

    func handleDismissGesture(sender: AnyObject) {
        Logger.debug("\(TAG) in \(#function)")
        self.dismiss(animated: true)
    }
}
