//
//  RedirectRulesSettingsViewController.swift
//  RedirectRulesSettingsViewController
//
//  Created by James Magahern on 6/25/21.
//

import UIKit

class RedirectRulesSettingsViewController: UICollectionViewController
{
    private enum Section {
        case rules
        case addButton
    }
    
    private enum Items: String {
        case addButton
    }
    
    private lazy var dataSource: UICollectionViewDiffableDataSource<Section, String> = {
        let registry = UICollectionView.CellRegistration<UICollectionViewListCell, String> { [unowned self] cell, indexPath, item in
            var config = cell.defaultContentConfiguration()
            if item == Items.addButton.rawValue {
                config.text = "Add Redirect Rule"
                config.textProperties.font = .preferredFont(forTextStyle: .subheadline)
                config.textProperties.alignment = .center
                config.image = .init(systemName: "plus.circle")
                
                cell.accessories = []
            } else {
                if let rule = Settings.shared.redirectRules[item] {
                    config.text = "\(item) → \(rule)"
                }
                
                let deleteOptions = UICellAccessory.DeleteOptions(isHidden: false, reservedLayoutWidth: nil, tintColor: .red, backgroundColor: nil)
                cell.accessories = [
                    .delete(displayed: .always, options: deleteOptions, actionHandler: { [unowned self] in
                        deleteRedirectRule(fromHost: item)
                    })
                ]
            }
            
            cell.contentConfiguration = config
        }
        
        return UICollectionViewDiffableDataSource<Section, String>(collectionView: collectionView) { (collectionView, indexPath, itemIdentifier) in
            collectionView.dequeueConfiguredReusableCell(using: registry, for: indexPath, item: itemIdentifier)
        }
    }()
    
    init() {
        let config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
        
        #if targetEnvironment(macCatalyst)
        let layout = UICollectionViewCompositionalLayout { section, layoutEnvironment in
            let listSection = NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment)
            listSection.contentInsets = NSDirectionalEdgeInsets(top: 24.0, leading: 164.0, bottom: 24.0, trailing: 164.0)
            
            return listSection
        }
        #else
        let layout = UICollectionViewCompositionalLayout.list(using: config)
        #endif
        
        super.init(collectionViewLayout: layout)
        
        tabBarItem.title = "Redirect Rules"
        tabBarItem.image = UIImage(systemName: "arrowshape.zigzag.forward")
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        var snapshot = dataSource.snapshot()
        snapshot.appendSections([ .rules, .addButton ])
        snapshot.appendItems(Settings.shared.redirectRules.keys.sorted(), toSection: .rules)
        snapshot.appendItems([ Items.addButton.rawValue ], toSection: .addButton)
        dataSource.applySnapshotUsingReloadData(snapshot)
    }
    
    override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        collectionView.deselectItem(at: indexPath, animated: true)
        
        let item = dataSource.itemIdentifier(for: indexPath)
        if item == Items.addButton.rawValue {
            let createRuleViewController = CreateRedirectRuleViewController()
            createRuleViewController.finishedCreatingRule = { [unowned self] (fromHost, toHost) in
                if fromHost.count > 0 && toHost.count > 0 {
                    addRedirectRule(fromHost: fromHost, toHost: toHost)
                }
            }
            
            let navController = UINavigationController(rootViewController: createRuleViewController)
            present(navController, animated: true, completion: nil)
        }
    }
    
    private func addRedirectRule(fromHost: String, toHost: String) {
        Settings.shared.redirectRules[fromHost] = toHost
        
        var snapshot = dataSource.snapshot()
        snapshot.appendItems([ fromHost ], toSection: .rules)
        dataSource.apply(snapshot, animatingDifferences: true)
    }
    
    private func deleteRedirectRule(fromHost: String) {
        Settings.shared.redirectRules.removeValue(forKey: fromHost)
        
        var snapshot = dataSource.snapshot()
        snapshot.deleteItems([ fromHost ])
        dataSource.apply(snapshot, animatingDifferences: true)
    }
}

class CreateRedirectRuleViewController: UICollectionViewController
{
    enum Section: Int {
        case header
        case fromHost
        case toHost
    }
    
    enum Item: Hashable {
        case header(section: Section)
        case textField(section: Section)
    }
    
    struct TextFieldCellConfiguration: UIContentConfiguration {
        var textField: UITextField
        
        func makeContentView() -> UIView & UIContentView {
            return GenericContentView<UITextField, TextFieldCellConfiguration>(configuration: self, view: textField) { _,_ in }
        }
        
        func updated(for state: UIConfigurationState) -> TextFieldCellConfiguration {
            self
        }
    }
    
    struct ImageViewCellConfiguration: UIContentConfiguration {
        var imageView: UIImageView
        
        func makeContentView() -> UIView & UIContentView {
            return GenericContentView<UIImageView, Self>(configuration: self, view: imageView) { _,_ in }
        }
        
        func updated(for state: UIConfigurationState) -> Self {
            self
        }
    }
    
    public var finishedCreatingRule: ((_ fromHost: String, _ toHost: String) -> Void)?
    
    private let sectionHeaderImageView = UIImageView(image: .init(systemName: "arrowshape.zigzag.forward"))
    private let fromHostField = UITextField(frame: .zero)
    private let toHostField = UITextField(frame: .zero)
    
    private let doneButton = UIBarButtonItem(systemItem: .done, primaryAction: nil, menu: nil)
    
    private lazy var dataSource: UICollectionViewDiffableDataSource<Section, Item> = {
        let listCellRegistry = UICollectionView.CellRegistration<UICollectionViewListCell, Item> { [unowned self] cell, indexPath, item in
            let section = dataSource.snapshot().sectionIdentifier(containingItem: item)
            
            switch item {
                case .header(_):
                    var contentConfig = cell.defaultContentConfiguration()
                    contentConfig.text = section == .fromHost ? "From Host" : "To Host"
                    cell.contentConfiguration = contentConfig
                case .textField(_):
                    cell.contentConfiguration = TextFieldCellConfiguration(textField:
                                                                            section == .fromHost ? fromHostField
                                                                                                 : toHostField)
            }
        }
        
        let headerCellRegistry = UICollectionView.CellRegistration<UICollectionViewCell, Item> { [unowned self] cell, indexPath, item in
            let config = ImageViewCellConfiguration(imageView: sectionHeaderImageView)
            cell.contentConfiguration = config
        }
        
        return UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView) { [unowned self] (collectionView, indexPath, itemIdentifier) in
            let section = self.dataSource.sectionIdentifier(for: indexPath.section)
            if section == .header {
                return collectionView.dequeueConfiguredReusableCell(using: headerCellRegistry, for: indexPath, item: itemIdentifier)
            } else {
                return collectionView.dequeueConfiguredReusableCell(using: listCellRegistry, for: indexPath, item: itemIdentifier)
            }
        }
    }()
    
    init() {
        var config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
        config.headerMode = .firstItemInSection
        
        let layout = UICollectionViewCompositionalLayout { (sectionIndex, environment) in
            let section = Section(rawValue: sectionIndex)
            if section == .header {
                let size = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(80.0))
                let group = NSCollectionLayoutGroup.vertical(
                    layoutSize: size,
                    subitems: [
                        NSCollectionLayoutItem(layoutSize: size)
                    ])
                return NSCollectionLayoutSection(group: group)
            } else {
                return NSCollectionLayoutSection.list(using: config, layoutEnvironment: environment)
            }
        }
        
        super.init(collectionViewLayout: layout)
        
        preferredContentSize = CGSize(width: -1, height: 320.0)
        
        self.title = "Add Redirect Rule"
        
        navigationItem.leftBarButtonItem = UIBarButtonItem(systemItem: .cancel, primaryAction: UIAction { [unowned self] _ in
            dismiss(animated: true, completion: nil)
        }, menu: nil)
        
        doneButton.primaryAction = UIAction { [unowned self] _ in
            finishedCreatingRule?(fromHostField.text!, toHostField.text!)
            dismiss(animated: true, completion: nil)
        }
        
        navigationItem.rightBarButtonItem = doneButton
        
        sectionHeaderImageView.contentMode = .scaleAspectFit
        
        fromHostField.placeholder = "fromhostname.com"
        fromHostField.autocorrectionType = .no
        fromHostField.autocapitalizationType = .none
        fromHostField.keyboardType = .URL
        fromHostField.returnKeyType = .next
        fromHostField.delegate = self
        
        toHostField.placeholder = "tohostname.com"
        toHostField.autocorrectionType = .no
        toHostField.autocapitalizationType = .none
        toHostField.keyboardType = .URL
        toHostField.returnKeyType = .done
        toHostField.delegate = self
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        var snapshot = dataSource.snapshot()
        snapshot.appendSections([ Section.header, Section.fromHost, Section.toHost ])
        snapshot.appendItems([ .header(section: .header) ], toSection: .header)
        snapshot.appendItems([ .header(section: .fromHost), .textField(section: .fromHost) ], toSection: .fromHost)
        snapshot.appendItems([ .header(section: .toHost), .textField(section: .toHost) ], toSection: .toHost)
        dataSource.applySnapshotUsingReloadData(snapshot)
    }
    
    override func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
        false
    }
}

extension CreateRedirectRuleViewController : UITextFieldDelegate {
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if textField == fromHostField {
            toHostField.becomeFirstResponder()
        } else if textField == toHostField {
            toHostField.resignFirstResponder()
        }
        
        return false
    }
}

