//
//  ViewController.swift
//  DRMTodayOfflineDemo
//
//

import PRESTOplay
import CastlabsApple
import CastlabsDownloader
import AVFoundation
import UIKit

class ViewController: UIViewController, DownloadDelegate {
    lazy var prefetcher = PRESTOplaySDK.shared.prefetcher(for: playerConfiguration)
    lazy var player = PRESTOplaySDK.shared.player()
    lazy var downloader = PRESTOplaySDK.shared.downloader()

    lazy var playerConfiguration: PlayerConfiguration = {
        let hlsStream = "https://example.com/index.m3u8"
        let playerConfig = PlayerConfiguration(with: URL(string: hlsStream)!)
        playerConfig.drmType = .custom
        playerConfig.drmSystem = .fairplay
        let drmConfig = DrmConfiguration()
        drmConfig.certificateUrl = URL(
            string: "...")!
        drmConfig.licensingUrl = URL(
            string: ".../?offline=true")!
        drmConfig.persistLicense = true

        let dict = [
            "merchant": "...",
            "userId": "...",
            "sessionId": "..."
        ]
        if let customData = try? JSONSerialization.data(
            withJSONObject: dict,
            options: []) {
            drmConfig.licensingParameters = [
                "dt-custom-data": customData.base64EncodedString(),
                "Content-Type": "application/x-www-form-urlencoded"
            ]
        }
        playerConfig.drmConfiguration = drmConfig
        return playerConfig
    }()
    

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view.
        // optional: ignore silent switch
        try? AVAudioSession.sharedInstance().setCategory(.playback)

        guard var prefetcher else { return }

        prefetcher.requestModifiers = [DRMTodayRequestModifier()]
        prefetcher.responseModifiers = [DRMTodayResponseModifier()]

        prefetcher.prefetchKeys { [weak self] error in
            guard let self else { return }
            print("Prefetch completed with error: \(String(describing: error))")
        }

        let alreadyDownloaded = downloader.getDownloads().contains {
            $0.playerConfiguration.contentUrl == playerConfiguration.contentUrl
        }

        if alreadyDownloaded {
            print("The stream is already downloaded")
            play()
        } else {
            print("Starting the stream download")
            download()
        }
    }

    override func viewWillTransition(to size: CGSize,
                                     with coordinator: UIViewControllerTransitionCoordinator) {
        player.update(size: size)
    }

    func download() {
        let download = downloader.createDownload(playerConfiguration, headers: [:])
        downloader.prepareDownload(download.uuid, completion: { download, error in
            if let error = error {
                print("Error:", error.message ?? "")
                return
            }

            guard let id = download?.uuid else { return }
            if let startError = self.downloader.startDownload(id, delegate: self) {
                print("Error:", startError.message ?? "")
            }
        })
    }

    func didStateChange(_ download: Download) {
        if download.state == .success {
            play()
        }
    }

    func didProgressChange(_ download: Download) {
        print("Progress: \(download.progress.percent)")
    }

    func play() {
        let localDownload = downloader.getDownloads().first { download in
            playerConfiguration.contentUrl == download.playerConfiguration.contentUrl
        }
        guard let download = localDownload else { return }
        let config = try! PlayerConfiguration(with: download)

        player.load(config: config)
        player.onState = { [weak self] previous, state in
            guard let self else { return }
            if let error = self.player.error {
                print("Error \(error)")
                return
            }
        }

        player.attach(to: view.layer)
        player.open(autoplay: true)
    }
}

// Prepare the license request for the DRMToday backend
struct DRMTodayRequestModifier: RequestModifierProtocol {
    func modify(_ request: Request,
                completionHandler: @escaping (Request?) -> Void) {
        // Generated Auth-Token
        request.headers["x-dt-auth-token"] = "..."

        guard request.type == .license else {
            completionHandler(request)
            return
        }

        let queryKeyValueString = CharacterSet(charactersIn: ":?=&+").inverted
        let encodedSpcMessage = request.data?.base64EncodedString()
            .addingPercentEncoding(
                withAllowedCharacters: queryKeyValueString) ?? ""
        
        let post = String(format: "spc=%@", encodedSpcMessage)

        request.data = post.data(using: .utf8, allowLossyConversion: true)
        completionHandler(request)
    }
}

// Parse the response returned from DRMToday backend
struct DRMTodayResponseModifier: ResponseModifierProtocol {
    func modify(_ response: Response,
                completionHandler: @escaping (Response?) -> Void) {
        guard response.type == .license else {
            completionHandler(response)
            return
        }

        response.data = Data(base64Encoded: response.data!)
        completionHandler(response)
    }
}
