import UIKit
import VisionKit

final class DocumentsTableViewController: UITableViewController {
  
  struct Constants {
    static let reuseIdentifier = String(describing: DocumentsTableViewController.self)
    static let storyboardName = "Documents"
    static let title = Bundle.appName
    static let rowHeight: CGFloat = 96
    static let cellReuseIdentifier = String(describing: DocumentsTableViewCell.self)
    
    static let topBottom: CGFloat = 120
    static let margin: CGFloat = 64
  }
  
  static func buildViewController() -> DocumentsTableViewController {
    let controller = UIStoryboard(name: Constants.storyboardName,
                                  bundle: .main).instantiateViewController(withIdentifier: Constants.reuseIdentifier)
    return controller as! DocumentsTableViewController
  }
  
  private var viewModels: [File] = []
  private var localFileManager: LocalFileManager?
  private var sortType: SortyFileType = .date
  
  private let noDocumentsimageView = UIImageView(image: UIImage(named: "box"))
  private var renameAlertController: UIAlertController?
  private var renameFileName: String?
  
  override func viewDidLoad() {
    super.viewDidLoad()
    navigationItem.title = Constants.title
    tableView.tableFooterView = UIView()
    localFileManager = LocalFileManager()
    
    tabBarController?.delegate = UIApplication.shared.delegate as? UITabBarControllerDelegate
    
    NotificationCenter.default.addObserver(self, selector: #selector(middleButtonTapped(_:)),
                                           name: NSNotification.Name.MiddleButtonTapped, object: nil)
    
    NotificationCenter.default.addObserver(self, selector: #selector(fetchViewModels),
                                           name: NSNotification.Name.ReloadViewModels, object: nil)
    
    if let view = navigationController?.view  {
      noDocumentsimageView.translatesAutoresizingMaskIntoConstraints = false
      noDocumentsimageView.contentMode = .scaleAspectFit
      view.addSubview(noDocumentsimageView)
      
      NSLayoutConstraint.activate([
        noDocumentsimageView.topAnchor.constraint(equalTo: view.topAnchor, constant: Constants.topBottom),
        noDocumentsimageView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -Constants.topBottom),
        noDocumentsimageView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: Constants.margin),
        noDocumentsimageView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -Constants.margin)
      ])
    }
    
    if UserDefaults.standard.startsAppWithCamera {
      openCamera()
    }
  }
  
  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    fetchViewModels()
  }
  
  deinit {
    NotificationCenter.default.removeObserver(self)
  }
  
  @objc private func fetchViewModels() {

    guard let directoryURL = localFileManager?.scannerURL,
          let viewModels = localFileManager?.filesForDirectory(directoryURL, sortType: sortType) else { return }
    self.viewModels = viewModels
    tableView.reloadData()
    
    if viewModels.isEmpty {
      noDocumentsimageView.isHidden = false
    } else {
      noDocumentsimageView.isHidden = true
    }
  }
  
  // MARK: - Table view data source
  
  override func numberOfSections(in tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
  }
  
  override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
    return viewModels.count
  }
  
  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCell(withIdentifier: Constants.cellReuseIdentifier,
                                                   for: indexPath) as? DocumentsTableViewCell else { return UITableViewCell() }
    
    // Configure the cell...
    let viewModel = viewModels[indexPath.row]
    cell.configure(with: viewModel, image: localFileManager?.getThumbnail(for: viewModel.fileURL))
    
    return cell
  }
   
  override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return Constants.rowHeight
  }
  
  override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let viewModel = viewModels[indexPath.row]
    let controller = DocumentPreviewViewController.buildViewController()
    controller.file = viewModel
    controller.hidesBottomBarWhenPushed = true
    navigationController?.pushViewController(controller, animated: true)
  }
  
  override func tableView(_ tableView: UITableView,
                          editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
    return .none
  }
  
  override func tableView(_ tableView: UITableView,
                          trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    
    // Trash action
    let trash = UIContextualAction(style: .destructive,
                                   title: "Delete".localized) { [weak self] (_, _, completionHandler) in
      self?.deleteFile(at: indexPath)
      completionHandler(true)
    }
    trash.backgroundColor = .systemRed
    trash.image = UIImage(systemName: "trash")?.tint(with: .white)
    
    // Rename action
    let rename = UIContextualAction(style: .normal,
                                    title: "Rename".localized) { [weak self] (_, _, completionHandler) in
      self?.renameFile(at: indexPath)
      completionHandler(true)
    }
    rename.backgroundColor = UIColor.black.withAlphaComponent(0.5)
    rename.image = UIImage(systemName: "square.and.pencil")?.tint(with: .white)
    
    let configuration = UISwipeActionsConfiguration(actions: [trash, rename])
    configuration.performsFirstActionWithFullSwipe = true
    
    return configuration
  }
  
  @objc private func middleButtonTapped(_ notification: NSNotification) {
    let alertController = UIAlertController(title: nil,
                                  message: nil, preferredStyle: .actionSheet)

    let cameraAction = UIAlertAction(title: "Camera".localized, style: .default, handler: { action in
      self.openCamera()
    })
    
    let galleryAction = UIAlertAction(title: "Gallery".localized, style: .default, handler: { action in
      self.openGallery()
    })
    
    alertController.addAction(cameraAction)
    cameraAction.setValue(UIImage(systemName: "camera"), forKey: "image")
    cameraAction.setValue(CATextLayerAlignmentMode.left, forKey: "titleTextAlignment")
    
    alertController.addAction(galleryAction)
    galleryAction.setValue(UIImage(systemName: "photo"), forKey: "image")
    galleryAction.setValue(CATextLayerAlignmentMode.left, forKey: "titleTextAlignment")
    
    alertController.addAction(UIAlertAction(title: "Cancel".localized, style: .cancel, handler: nil))
    alertController.popoverPresentationController?.sourceView = notification.object as? UIButton
    present(alertController, animated: true)
  }
  
  private func openCamera() {
      let scannerOptions = ImageScannerOptions(scanMultipleItems: true,
                                                       allowAutoScan: false,
                                                       allowTapToFocus: false,
                                                       defaultColorRenderOption:.color)
      let scannerViewController = ImageScannerController(options: scannerOptions)
    scannerViewController.imageScannerDelegate = self
    present(scannerViewController, animated: true)
  }
  
  private func openGallery() {
    guard UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum) else { return }
    let imagePickerController = UIImagePickerController()
    imagePickerController.delegate = self
    
    imagePickerController.sourceType = UIImagePickerController.SourceType.savedPhotosAlbum
    imagePickerController.allowsEditing = UserDefaults.standard.isPhotoEditigOn
    present(imagePickerController, animated: true, completion: nil)
  }

  private func renameFile(at indexPath: IndexPath) {
    let viewModel = viewModels[indexPath.row]
    renameAlertController = UIAlertController(title: "Rename document".localized, message: nil, preferredStyle: .alert)
    
    renameAlertController!.addTextField { [weak self] textField in
      guard let self = self else { return }
      textField.placeholder = viewModel.displayName
      textField.text = viewModel.displayName
      textField.clearButtonMode = .always
      self.renameFileName = viewModel.displayName
      textField.addTarget(self, action: #selector(self.textFieldDidChange(_:)), for: .editingChanged)
    }
    
    let continueAction = UIAlertAction(title: "Rename".localized,
                                       style: .default) { [weak self] _ in
      guard let self = self else { return }
      guard let textFields = self.renameAlertController?.textFields else { return }
      
      if let newName = textFields.first?.text, newName != viewModel.displayName {
        do {
          try self.localFileManager?.renameFile(at: viewModel.fileURL, withName: newName)
          self.fetchViewModels()
        } catch {
          return
        }
      }
    }

    renameAlertController!.addAction(continueAction)
    renameAlertController!.addAction(UIAlertAction(title: "Cancel".localized, style: .cancel, handler: nil))
    renameAlertController?.actions.first?.isEnabled = false
    present(renameAlertController!, animated: true)
  }
  
  private func deleteFile(at indexPath: IndexPath) {
    let viewModel = viewModels[indexPath.row]

    if UserDefaults.standard.askOnSwipeDelete {
      let alertController = UIAlertController(title: Bundle.appName,
                                              message: "Are you sure you want to delete this document?".localized, preferredStyle: .alert)
            
      let okAction = UIAlertAction(title: "Yes, delete!".localized, style: .destructive, handler: { [weak self] action in
        guard let self = self else { return }
        
        self.delete(file: viewModel.fileURL, at: indexPath)
      })
      
      alertController.addAction(okAction)
      
      alertController.addAction(UIAlertAction(title: "Cancel".localized, style: .cancel, handler: nil))
      alertController.popoverPresentationController?.sourceView = tableView.cellForRow(at: indexPath)
      present(alertController, animated: true)
    } else {
      delete(file: viewModel.fileURL, at: indexPath)
    }
  }
  
  private func delete(file fileURL: URL, at indexPath: IndexPath) {
    do {
      try self.localFileManager?.filesManager.removeItem(at: fileURL)
      try self.localFileManager?.removeThumbnail(for: fileURL)
      self.viewModels.remove(at: indexPath.row)
      self.tableView.deleteRows(at: [indexPath], with: .fade)
    } catch {
      return
    }
    if self.viewModels.isEmpty {
      self.noDocumentsimageView.isHidden = false
    }
  }
}

/// Tells the delegate that the user picked a still image.
extension DocumentsTableViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate {
  /// Your delegate object’s implementation of this method should pass the specified media on to any custom code that needs it, and should then dismiss the picker view.
  /// When editing is enabled, the image picker view presents the user with a preview of the currently selected image or movie along with controls for modifying it.
  /// (This behavior is managed by the picker view prior to calling this method.) If the user modifies the image or movie, the editing information is available in the info parameter.
  /// The original image is also returned in the info parameter.
  func imagePickerController(_ picker: UIImagePickerController,
                             didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    picker.dismiss(animated: true) { [weak self] in
      guard let self = self else { return }
      guard let image = info[UserDefaults.standard.isPhotoEditigOn ? UIImagePickerController.InfoKey.editedImage : UIImagePickerController.InfoKey.originalImage] as? UIImage else { return }
      PDFManager.createPDFDocument(from: image, localFileManager: self.localFileManager)
      self.fetchViewModels()
    }
  }
}

extension DocumentsTableViewController: ImageScannerControllerDelegate {
    func imageScannerController(_ scanner: ImageScannerController, didFinishWithSession session: MultiPageScanSession) {
        var images = [URL]()
        
        for index in 0..<session.scannedItems.count {
            if let url = session.scannedItems[index].renderedImage {
                images.append(url)
            }
        }
        print("images: \(images)")
        
        PDFManager.createMultiPDFPage(from: images, localFileManager: localFileManager) {
            scanner.dismiss(animated: true) {
              self.fetchViewModels()
            }
        }
    }
    
    func imageScannerControllerDidCancel(_ scanner: ImageScannerController) {
        scanner.dismiss(animated: true)
    }
    
    func imageScannerController(_ scanner: ImageScannerController, didFailWithError error: Error) {
        scanner.dismiss(animated: true)

    }
  
  @objc func textFieldDidChange(_ textField: UITextField) {
    guard let text = textField.text, let renameFileName = renameFileName,
          renameFileName != text, !text.trimmingCharacters(in: .whitespaces).isEmpty else {
      renameAlertController?.actions.first?.isEnabled = false
      return
    }
    
    renameAlertController?.actions.first?.isEnabled = true
  }
}