import UIKit
import Kingfisher
import LinkPresentation
import RealmSwift
import Eureka

class ReportController: FormViewController, MediaBrowserViewControllerDataSource, MediaBrowserViewControllerDelegate, UIActivityItemSource {

    @IBOutlet weak var actionBarItem: UIBarButtonItem!
    @IBOutlet weak var copyBarItem: UIBarButtonItem!
    
    private var reportImageUrl: URL?
    private let logoPlaceholder = UIImage(named: "SteeringWheel")

    var vehicle: Vehicle? {
        didSet {
            loadViewIfNeeded()
            self.updateReport()
            self.form.allSections.forEach { $0.reload() }
            self.navigationController?.setNavigationBarHidden(self.vehicle == nil, animated: false)
        }
    }
    
    private var notificationToken: NotificationToken?
    var number: String? {
        didSet {
            if let realm = try? Realm(), let num = number {
                let vehicles = realm.objects(Vehicle.self).filter("number = %@", num)
                self.notificationToken?.invalidate()
                self.notificationToken = vehicles.observe { _ in self.vehicle = vehicles.first }
            } else {
                self.vehicle = nil
            }
        }
    }
    
    // MARK: - Lifecycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        if let vehicle = self.vehicle {
            let urls = Array(vehicle.photos.compactMap { URL(string: $0.url) })
            let prefetcher = ImagePrefetcher(urls: urls)
            prefetcher.start()
        }
        
        form +++ Section()
            <<< LabelRow("Model").cellUpdate { cell, _ in cell.imageView?.kf.setImage(with: URL(string: self.vehicle?.brand?.logo ?? ""), placeholder: self.logoPlaceholder) }
        
        form +++ Section(NSLocalizedString("General", comment: ""))
            <<< LabelRow("Year") { $0.title = NSLocalizedString("Year", comment: "") }
            <<< LabelRow("Color") { $0.title = NSLocalizedString("Color", comment: "") }
            <<< LabelRow("Category") { $0.title = NSLocalizedString("Category", comment: "") }
            <<< LabelRow("STP") { $0.title = NSLocalizedString("Steering wheel position", comment: "") }
            <<< LabelRow("Japanese") { $0.title = NSLocalizedString("Japanese", comment: "") }
        
        form +++ Section(NSLocalizedString("Identifiers", comment: ""))
            <<< LabelRow("PlateNumber") { $0.title = NSLocalizedString("Plate number", comment: "") }
            <<< LabelRow("VIN") { $0.title = NSLocalizedString("VIN", comment: "") }
            <<< LabelRow("STS") { $0.title = NSLocalizedString("STS", comment: "") }
            <<< LabelRow("PTS") { $0.title = NSLocalizedString("PTS", comment: "") }
        
        form +++ Section(NSLocalizedString("Engine", comment: ""))
            <<< LabelRow("EngineNumber") { $0.title = NSLocalizedString("Number", comment: "") }
            <<< LabelRow("FuelType") { $0.title = NSLocalizedString("Fuel type", comment: "") }
            <<< LabelRow("Volume") { $0.title = NSLocalizedString("Volume (cm³)", comment: "") }
            <<< LabelRow("PowerHP") { $0.title = NSLocalizedString("Power (HP)", comment: "") }
            <<< LabelRow("PowerKw") { $0.title = NSLocalizedString("Power (kw)", comment: "") }
        
        form +++ Section(NSLocalizedString("History", comment: ""))
            <<< LabelRow("Events") { $0.title = NSLocalizedString("Events", comment: "") }
            .cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator }
            .onCellSelection { _, _ in
                let sb = UIStoryboard(name: "Main", bundle: nil)
                let controller = sb.instantiateViewController(identifier: "EventsController") as EventsController
                controller.vehicle = self.vehicle
                self.navigationController?.pushViewController(controller, animated: true)
            }
            
            <<< LabelRow("OSAGO") { $0.title = NSLocalizedString("OSAGO", comment: "") }
            .cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator }
            .onCellSelection { _, _ in
                let sb = UIStoryboard(name: "Main", bundle: nil)
                let controller = sb.instantiateViewController(identifier: "OsagoController") as OsagoController
                controller.vehicle = self.vehicle
                self.navigationController?.pushViewController(controller, animated: true)
            }
            
            <<< LabelRow("Owners") { row in
                row.title = NSLocalizedString("Owners", comment: "")
                row.disabled = "$Owners == '0'"
            }
            .cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator }
            .onCellSelection { _, row in
                if row.value != "0" {
                    let sb = UIStoryboard(name: "Main", bundle: nil)
                    let controller = sb.instantiateViewController(identifier: "OwnersController") as OwnersController
                    controller.owners = self.vehicle?.ownershipPeriods.toArray() ?? []
                    self.navigationController?.pushViewController(controller, animated: true)
                }
            }
            
            <<< LabelRow("Photos") { row in
                row.title = NSLocalizedString("Photos", comment: "")
                row.disabled = "$Photos == '0'"
            }
            .cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator }
            .onCellSelection { _, row in
                if row.value != "0" {
                    let mediaBrowser = MediaBrowserViewController(index: 0, dataSource: self, delegate: self)
                    mediaBrowser.shouldShowTitle = true
                    mediaBrowser.title = self.vehicle?.photos.first?.description
                    self.present(mediaBrowser, animated: true, completion: nil)
                }
            }
        
            <<< LabelRow("Ads") { row in
                row.title = NSLocalizedString("Ads", comment: "")
                row.disabled = "$Ads == '0'"
            }
            .cellUpdate { cell, _ in cell.accessoryType = .disclosureIndicator }
            .onCellSelection { _, row in
                let controller = AdsController()
                controller.ads = self.vehicle?.ads.toArray() ?? []
                self.navigationController?.pushViewController(controller, animated: true)
            }
        
        if Settings.shared.showDebugInfo {
            self.form +++ Section(NSLocalizedString("Debug info", comment: "noun"))
                <<< SourceStatusRow("DebugAutocod") { $0.title = NSLocalizedString("Autocod", comment: "") }
                <<< SourceStatusRow("DebugVin01Vin") { $0.title = NSLocalizedString("Vin01 (VIN)", comment: "") }
                <<< SourceStatusRow("DebugVin01Base") { $0.title = NSLocalizedString("Vin01 (base)", comment: "base report") }
                <<< SourceStatusRow("DebugVin01History") { $0.title = NSLocalizedString("Vin01 (history)", comment: "GIBDD registration history") }
                <<< SourceStatusRow("DebugNomerogram") { $0.title = NSLocalizedString("Nomerogram", comment: "") }
        }
    }
    
    func row(_ tag: String) -> LabelRow? {
        self.form.rowBy(tag: tag) as? LabelRow
    }
    
    func sourceStatusRow(_ tag: String) -> SourceStatusRow? {
        self.form.rowBy(tag: tag) as? SourceStatusRow
    }
    
    func updateReport() {
        self.row("Model")?.value = self.vehicle?.brand?.name?.original ?? "<unknown>"
        self.row("Year")?.value = String(self.vehicle?.year ?? 0)
        self.row("Color")?.value = self.vehicle?.color ?? "<unknown>"
        self.row("Category")?.value = self.vehicle?.category ?? "<unknown>"
        self.row("STP")?.value = self.stringFromBool(self.vehicle?.isRightWheel.value, yes: NSLocalizedString("Right", comment: ""), no: NSLocalizedString("Left", comment: ""))
        self.row("Japanese")?.value = self.stringFromBool(self.vehicle?.isJapanese.value, yes: NSLocalizedString("Yes", comment: ""), no: NSLocalizedString("No", comment: ""))
        
        var num = self.vehicle?.getNumber() ?? "<unknown>"
        if self.vehicle?.outdated ?? false, let current = self.vehicle?.currentNumber {
            num = "\(self.vehicle!.getNumber()) (\(current))"
        }
        self.row("PlateNumber")?.value = num
        
        self.row("VIN")?.value = self.vehicle?.vin1 ?? "<unknown>"
        self.row("STS")?.value = self.vehicle?.sts ?? "<unknown>"
        self.row("PTS")?.value = self.vehicle?.pts ?? "<unknown>"
        self.row("EngineNumber")?.value = self.vehicle?.engine?.number ?? "<unknown>"
        self.row("FuelType")?.value = self.vehicle?.engine?.fuelType ?? "<unknown>"
        self.row("Volume")?.value = String(self.vehicle?.engine?.volume.value ?? 0)
        self.row("PowerHP")?.value = String(self.vehicle?.engine?.powerHp ?? 0)
        self.row("PowerKw")?.value = String(self.vehicle?.engine?.powerKw.value ?? 0)
        self.row("Events")?.value = String(self.vehicle?.events.count ?? 0)
        self.row("OSAGO")?.value = String(self.vehicle?.osagoContracts.count ?? 0)
        self.row("Owners")?.value = String(self.vehicle?.ownershipPeriods.count ?? 0)
        self.row("Photos")?.value = String(self.vehicle?.photos.count ?? 0)
        self.row("Ads")?.value = String(self.vehicle?.ads.count ?? 0)
        
        if let dInfo = self.vehicle?.debugInfo {
            self.sourceStatusRow("DebugAutocod")?.value = dInfo.autocod
            self.sourceStatusRow("DebugVin01Vin")?.value = dInfo.vin01vin
            self.sourceStatusRow("DebugVin01Base")?.value = dInfo.vin01base
            self.sourceStatusRow("DebugVin01History")?.value = dInfo.vin01history
            self.sourceStatusRow("DebugNomerogram")?.value = dInfo.nomerogram
        }
    }
    
    func stringFromBool(_ value: Bool?, yes: String, no: String) -> String {
        guard let value = value else { return "<unknown>" }
        return value ? yes : no
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        guard let ad = UIApplication.shared.delegate as? AppDelegate else { return }
        
        self.navigationController?.setNavigationBarHidden(self.vehicle == nil, animated: animated)
        
        switch ad.quickAction {
        case .check:
            self.dismiss(animated: false, completion: nil)
        default:
            break
        }
        
        self.form.allSections.forEach { $0.reload() }
    }
    
    // MARK: - MediaBrowserViewControllerDataSource & MediaBrowserViewControllerDelegate
    
    func numberOfItems(in mediaBrowser: MediaBrowserViewController) -> Int {
        guard let images = self.vehicle?.photos else { return 0 }
        return images.count
    }

    func mediaBrowser(_ mediaBrowser: MediaBrowserViewController, imageAt index: Int, completion: @escaping MediaBrowserViewControllerDataSource.CompletionBlock) {
        guard let images = self.vehicle?.photos, let url = URL(string: images[index].url) else {
            completion(index, nil, ZoomScale.default, NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Image not found"]))
            return
        }
        
        KingfisherManager.shared.retrieveImage(with: url) { result in
            switch result {
            case .success(let res):
                completion(index, res.image, ZoomScale.default, nil)
                break
            case .failure(let error):
                completion(index, nil, ZoomScale.default, error)
                break
            }
        }
    }
    
    func mediaBrowser(_ mediaBrowser: MediaBrowserViewController, didChangeFocusTo index: Int) {
        guard let photo = self.vehicle?.photos[index] else { return }
        mediaBrowser.title = photo.description
    }
    
    // MARK: - Sharing
    
    @IBAction func onShare(_ sender: UIBarButtonItem) {
        guard let vehicle = self.vehicle else { return }
        
        let sheet = UIAlertController(title: NSLocalizedString("Share report", comment: ""), message: nil, preferredStyle: .actionSheet)
        sheet.popoverPresentationController?.barButtonItem = self.actionBarItem
        
        let cancel = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel) { _ in sheet.dismiss(animated: true, completion: nil) }
        let shareImage = UIAlertAction(title: NSLocalizedString("As one image", comment: ""), style: .default) { _ in
            let image = vehicle.reportImage(width: self.tableView.contentSize.width)
            
            do {
                let fm = FileManager.default
                let documentDirectory = try fm.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create:false)
                let fileURL = documentDirectory.appendingPathComponent("report.png")
                if let imageData = image.pngData() {
                    try imageData.write(to: fileURL)
                    self.reportImageUrl = fileURL
                }
                
                let controller = UIActivityViewController(activityItems: [self], applicationActivities: nil)
                controller.popoverPresentationController?.barButtonItem = sender
                self.present(controller, animated: true)
            } catch {
                print(error)
            }
        }
        
        let shareTextAndImage = UIAlertAction(title: NSLocalizedString("As text and photos", comment: ""), style: .default) { _ in
            guard let vehicle = self.vehicle else { return }
            var items: [Any] = [vehicle.reportText()]
            for photo in vehicle.photos {
                if let url = URL(string: photo.url) {
                    if let image = ImageCache.default.retrieveImageInDiskCache(forKey: url.cacheKey) {
                        items.append(image)
                    }

                }
            }
            
            let controller = UIActivityViewController(activityItems: items, applicationActivities: nil)
            controller.popoverPresentationController?.barButtonItem = sender
            self.present(controller, animated: true)
        }
        
        let shareLink = UIAlertAction(title: NSLocalizedString("As link", comment: ""), style: .default) { _ in
            guard let vehicle = self.vehicle else { return }
            
            if let jwt = try? JWT<EmptyPayload>.generate(for: vehicle.getNumber()), let url = URL(string: Constants.reportLinkBaseURL + "?token=" + jwt) {
                let controller = UIActivityViewController(activityItems: [url], applicationActivities: nil)
                controller.popoverPresentationController?.barButtonItem = sender
                self.present(controller, animated: true)
            }
        }
        
        sheet.addAction(shareImage)
        sheet.addAction(shareTextAndImage)
        sheet.addAction(shareLink)
        sheet.addAction(cancel)
        self.present(sheet, animated: true, completion: nil)
    }
    
    func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
        return UIImage()
    }
    
    func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
        return self.reportImageUrl
    }
    
    func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? {
        guard let url = self.reportImageUrl else { return nil }
        
        let metadata = LPLinkMetadata()
        metadata.title = self.vehicle?.getNumber()
        metadata.originalURL = url
        metadata.url = url
        metadata.imageProvider = NSItemProvider.init(contentsOf: url)
        metadata.iconProvider = NSItemProvider.init(contentsOf: url)
        return metadata
    }
    
    // MARK: - Copy
    
    @IBAction func onCopy(_ sender: UIBarButtonItem) {
        let sheet = UIAlertController(title: NSLocalizedString("Copy to pasteboard", comment: ""), message: nil, preferredStyle: .actionSheet)
        sheet.popoverPresentationController?.barButtonItem = self.copyBarItem
        let cancel = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel) { _ in sheet.dismiss(animated: true, completion: nil) }
        let copyPlateNumber = UIAlertAction(title: NSLocalizedString("Plate number", comment: ""), style: .default) { _ in UIPasteboard.general.string = self.vehicle?.getNumber() }
        let copyVin = UIAlertAction(title: NSLocalizedString("VIN", comment: ""), style: .default) { _ in UIPasteboard.general.string = self.vehicle?.vin1 }
        sheet.addAction(copyPlateNumber)
        sheet.addAction(copyVin)
        sheet.addAction(cancel)
        self.present(sheet, animated: true, completion: nil)
    }
}
