//
//  ScriptPolicyViewController.swift
//  SBrowser
//
//  Created by James Magahern on 7/24/20.
//

import UIKit

class ScriptOriginPolicyViewController: UIViewController, UICollectionViewDelegate
{
    var collectionView: UICollectionView?
    var allowScriptsForTab = false
    weak var delegate: ScriptPolicyViewControllerDelegate? = nil
    
    private var dataSource: UICollectionViewDiffableDataSource<Section, String>?
    private var didChangeScriptPolicy = false
    
    private enum Section: Int {
        case tabOptions
        case origins
    }
    
    private static let enableScriptsForTabItem: String = "enableScriptsForTab"
    
    convenience init(policyManager: ResourcePolicyManager, hostOrigin: String, loadedScripts: Set<String>, scriptsAllowedForTab: Bool) {
        self.init(nibName: nil, bundle: nil)
        allowScriptsForTab = scriptsAllowedForTab
        
        let listConfig = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
        let listLayout = UICollectionViewCompositionalLayout.list(using: listConfig)
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: listLayout)
        
        // Make sure host origin goes first in the list.
        let otherOriginScripts = loadedScripts.subtracting([ hostOrigin ])
        let allowedScripts = otherOriginScripts.filter { policyManager.allowedOriginsForScriptResources().contains($0) }
        
        let originItems = [ hostOrigin ] + allowedScripts + otherOriginScripts.subtracting(allowedScripts)
        
        let switchCellRegistry = UICollectionView.CellRegistration<UICollectionViewListCell, String> { [unowned self] (listCell, indexPath, item) in
            var config = listCell.defaultContentConfiguration()
            if item == Self.enableScriptsForTabItem {
                if allowScriptsForTab {
                    config.text = "Shields Up"
                    config.image = UIImage(systemName: "shield.fill")
                } else {
                    config.text = "Allow for Tab"
                    config.image = UIImage(systemName: "shield.slash")
                }
                
                config.textProperties.color = UIColor.systemBlue
            }
            
            listCell.contentConfiguration = config
        }
        
        let scriptPolicyRegistry = UICollectionView.CellRegistration<UICollectionViewListCell, String> { [unowned self] (listCell, indexPath, item) in
            var config = listCell.defaultContentConfiguration()
            config.text = item
            
            listCell.contentConfiguration = config
            
            let segmentedControl = UISegmentedControl(items: [
                UIImage(systemName: "xmark.seal")!,             // Disabled
                UIImage(systemName: "checkmark.seal.fill")!     // Enabled
            ])
            
            segmentedControl.setTitleTextAttributes([ .foregroundColor: UIColor.init(dynamicProvider: { traits in
                if traits.userInterfaceStyle == .dark {
                    return UIColor.systemTeal
                } else {
                    return UIColor.systemBlue
                }
            }) ], for: .selected)
            
            segmentedControl.addAction(UIAction(handler: { [unowned segmentedControl] _ in
                let allowed: Bool = (segmentedControl.selectedSegmentIndex == 1)
                
                if allowed {
                    policyManager.allowOriginToLoadScriptResources(item)
                } else {
                    policyManager.disallowOriginToLoadScriptResources(item)
                }
                
                if item == hostOrigin {
                    if var snapshot = self.dataSource?.snapshot() {
                        snapshot.reloadItems(Array(otherOriginScripts))
                        self.dataSource?.apply(snapshot, animatingDifferences: true)
                    }
                }
                
                self.didChangeScriptPolicy = true

            }), for: .valueChanged)
            
            if policyManager.allowedOriginsForScriptResources().contains(item) {
                segmentedControl.selectedSegmentIndex = 1
            } else {
                segmentedControl.selectedSegmentIndex = 0
            }
            
            let customViewConfiguration = UICellAccessory.CustomViewConfiguration(
                customView: segmentedControl,
                placement: .trailing(displayed: .always, at: { _ in return 0 }),
                isHidden: false,
                reservedLayoutWidth: .actual,
                tintColor: nil,
                maintainsFixedSize: true
            )
            
            listCell.accessories = [
                .customView(configuration: customViewConfiguration)
            ]
        }
        
        let dataSource = UICollectionViewDiffableDataSource<Section, String>(collectionView: collectionView) { (collectionView, indexPath, item) -> UICollectionViewCell? in
            if item == Self.enableScriptsForTabItem {
                return collectionView.dequeueConfiguredReusableCell(using: switchCellRegistry, for: indexPath, item: item)
            }
            
            return collectionView.dequeueConfiguredReusableCell(using: scriptPolicyRegistry, for: indexPath, item: item)
        }
        
        collectionView.dataSource = dataSource
        collectionView.delegate = self
        
        var snapshot = dataSource.snapshot()
        snapshot.appendSections([ .tabOptions ])
        snapshot.appendItems([ Self.enableScriptsForTabItem ], toSection: .tabOptions)
        
        if !allowScriptsForTab {
            snapshot.appendSections([ .origins ])
            snapshot.appendItems(originItems, toSection: .origins)
        }
        
        dataSource.apply(snapshot)
        
        self.dataSource = dataSource
        self.collectionView = collectionView
        
        title = "Script Origin Policy"
        navigationItem.rightBarButtonItem = UIBarButtonItem(systemItem: .done, primaryAction: UIAction(handler: { [unowned self] action in
            if self.didChangeScriptPolicy {
                self.delegate?.didChangeScriptPolicy()
                self.delegate?.setScriptsEnabledForTab(self.allowScriptsForTab)
            }
            
            self.dismiss(animated: true, completion: nil)
        }), menu: nil)
    }
    
    override func loadView() {
        self.view = collectionView
        self.view.backgroundColor = .systemGroupedBackground
    }
    
    // MARK: UICollectionViewDelegate
    
    func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool {
        indexPath.section != Section.origins.rawValue
    }
    
    func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
        indexPath.section != Section.origins.rawValue
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        guard let dataSource = dataSource else { return }
        
        if indexPath.section == Section.tabOptions.rawValue {
            let identifier = dataSource.itemIdentifier(for: indexPath)
            if identifier == Self.enableScriptsForTabItem {
                self.allowScriptsForTab = !self.allowScriptsForTab
                
                // Immediately notify and dismiss
                self.delegate?.didChangeScriptPolicy()
                self.delegate?.setScriptsEnabledForTab(self.allowScriptsForTab)
                self.dismiss(animated: true, completion: nil)
            }
        }
    }
}
