import UIKit
import PDFKit
import VisionKit
import PhotosUI

final class DocumentsTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    struct Constants {
        static let reuseIdentifier = String(describing: DocumentsTableViewController.self)
        static let storyboardName = "Documents"
        static let rowHeight: CGFloat = 112
        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
    }
    
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var AllFolderView: AllFolderTableViewCell!
    @IBOutlet weak var fixedTableSheet: UIView!
    @IBOutlet weak var searchForFilesView: SearchFilesView!
    
    @IBOutlet weak var noFilesLabel: UILabel!
    private var viewModels: [File] = []
    private var searchedViewModel: [File] = []
    
    private var sortType: SortyFileType = .date
    var options:ImageScannerOptions!
    var scannedItem = ScannedItem(originalImage: UIImage())
    var images: [UIImage] = []
    
    //    private let noDocumentsimageView = UIImageView(image: UIImage(named: "box"))
    private var renameAlertController: UIAlertController?
    private var renameFileName: String?
    
    private var selectedFolder: AppConfigurator.Folder?
    
    private var isSearching: Bool = false
    private var pageViewControllers: [UIViewController] = []
    private var scanSession: MultiPageScanSession?
    
    @IBOutlet weak var allFolderView_height: NSLayoutConstraint!
    private var localFileManager: LocalFileManager?
    override func viewDidLoad() {
        super.viewDidLoad()
        let defaults = UserDefaults.standard
        let decoder = JSONDecoder()
        if let savedData = defaults.object(forKey: "pdfDocumentObjects") as? Data {
            if let loadedPDFDocumentObjects = try? decoder.decode([PDFDocumentObject].self, from: savedData) {
                // loadedPDFDocumentObjects is your array of PDFDocumentObject instances
                for pdfDocument in loadedPDFDocumentObjects {
//                    if pdfDocument.fileURL == viewModel.fileURL {
                        print("*****count****:\(pdfDocument.session.scannedItems.count)")
//                    }
                }
            }
        }
        scanSession =  MultiPageScanSession()
        options = ImageScannerOptions()
        navigationItem.title = .fileManager.localized
        let settingsButton = UIBarButtonItem(image: UIImage(named: "settings"), style: .done, target: self, action: #selector(openSettings))
        navigationItem.rightBarButtonItem = settingsButton
        
        tableView.register(UINib(nibName: "DocumentsTableViewCell", bundle: nil), forCellReuseIdentifier: "DocumentsTableViewCell")
        
        tableView.tableFooterView = UIView()
        tableView.delegate = self
        tableView.dataSource = self
        
        tableView.reloadData()
        
        let savedFolders = AppConfigurator().getFolders()
        for item in savedFolders {
            if item.isSelected == true {
                selectedFolder = item
            }
        }
        
        if let folder = selectedFolder {
            AllFolderView?.set(selectedFolder: folder, delegate: self)
        }
        searchForFilesView.delegate = self
        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)
        
        NotificationCenter.default.addObserver(self, selector: #selector(rightButtonTapped(_:)),
                                               name: NSNotification.Name.rightButtonTapped, object: nil)
        if UserDefaults.standard.startsAppWithCamera {
            openCamera()
        }
        
        fixedTableSheet.layer.cornerRadius = 30
        fixedTableSheet.layer.shadowColor = UIColor.gray.cgColor
        fixedTableSheet.layer.shadowOffset = CGSize(width: 0, height: 2) // Shadow position
        fixedTableSheet.layer.shadowOpacity = 0.7 // Shadow opacity
        fixedTableSheet.layer.shadowRadius = 4.0
        fixedTableSheet.backgroundColor = .white // or any non-clear color
        fixedTableSheet.clipsToBounds = false
        noFilesLabel.set(text: .noFilesToShow.localized, color: .mainText, font: .medium(22))
        noFilesLabel.isHidden = true
        fetchViewModels()
        
        navigationController?.navigationBar.prefersLargeTitles = false
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        scanSession?.removeAll()
        self.tabBarController?.tabBar.isHidden = false
        fetchViewModels()
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    @objc private func fetchViewModels() {
        if let folder = selectedFolder {
            guard let directoryURL = localFileManager?.getFolderUrl(folder: folder),
                  let viewModels = localFileManager?.filesForDirectory(directoryURL, sortType: sortType) else { return }
            self.viewModels = viewModels
            self.searchedViewModel = viewModels
            AllFolderView?.set(selectedFolder: folder, delegate: self)
            
            if viewModels.isEmpty {
                noFilesLabel.isHidden = false
            } else {
                noFilesLabel.isHidden = true
            }
            tableView.reloadData()
        }
    }
    
    @objc private func openSettings() {
        if #available(iOS 16.0, *) {
            let liveScan  = DataScannerViewController(recognizedDataTypes: [.text()],
                                                      qualityLevel: .balanced,
                                                      isHighlightingEnabled: true)
            liveScan.delegate = self
            try? liveScan.startScanning()
            self.present(liveScan, animated: true)
        } else {
            let settings = SettingViewController()
            self.navigationController?.pushViewController(settings, animated: false)
        }
    }
    
    func extractImage(from pdfDocument: PDFDocument, at pageIndex: Int) -> ScannedItem? {
        guard pageIndex < pdfDocument.pageCount, let page = pdfDocument.page(at: pageIndex) else { return nil }
        
        var pageBounds = page.bounds(for: .mediaBox)
        
        // Calculate the scale factor to downsample the image
        let maxDimension: CGFloat = 4096.0  // Adjust this value as needed
        let scaleFactor = min(maxDimension / pageBounds.width, maxDimension / pageBounds.height)
        
        // Downsample the image
        pageBounds.size.width *= scaleFactor
        pageBounds.size.height *= scaleFactor
        
        let renderer = UIGraphicsImageRenderer(size: pageBounds.size)
        
        let image = renderer.image { (context) in
            UIColor.white.set()
            context.fill(pageBounds)
            
            context.cgContext.translateBy(x: 0.0, y: pageBounds.size.height)
            context.cgContext.scaleBy(x: 1.0, y: -1.0)
            
            context.cgContext.drawPDFPage(page.pageRef!)
        }
        self.scannedItem = ScannedItem(originalImage: image,renderImage: image)
        return scannedItem
    }
    
    
    // MARK: - Table view data source
    
    func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return isSearching ? searchedViewModel.count :viewModels.count
    }
    
    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 = isSearching ? searchedViewModel[indexPath.row ] : viewModels[indexPath.row]
        cell.configure(with: viewModel, image: localFileManager?.getThumbnail(for: viewModel.fileURL))
        
        return cell
        
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return Constants.rowHeight
    }
    
    func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
        return UIView()
    }
    
    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        20
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let viewModel = isSearching ? searchedViewModel[indexPath.row] : viewModels[indexPath.row]
        var session: MultiPageScanSession?
        let defaults = UserDefaults.standard
        let decoder = JSONDecoder()
        if let savedData = defaults.object(forKey: "pdfDocumentObjects") as? Data {
            if let loadedPDFDocumentObjects = try? decoder.decode([PDFDocumentObject].self, from: savedData) {
                // loadedPDFDocumentObjects is your array of PDFDocumentObject instances
                for pdfDocument in loadedPDFDocumentObjects {
                    if pdfDocument.name == viewModel.displayName {
                        session = pdfDocument.session
                    }
                }
            }
        }
        let controller = DocumentPreviewViewController.buildViewController()
        controller.file = viewModel
        controller.session = session
        controller.selectedFolder = self.selectedFolder
        controller.hidesBottomBarWhenPushed = true
        navigationController?.pushViewController(controller, animated: true)
    }
    
    func tableView(_ tableView: UITableView,
                   editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
        return .none
    }
    
    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 move = UIContextualAction(style: .normal,
                                      title: .move.localized) { [weak self] (_, _, completionHandler) in
            if let viewModel = self?.isSearching == true ? self?.searchedViewModel[indexPath.row] : self?.viewModels[indexPath.row] {
                self?.moveto(file: viewModel)
            }
            completionHandler(true)
        }
        
        let configuration = UISwipeActionsConfiguration(actions: [trash, rename, move])
        configuration.performsFirstActionWithFullSwipe = true
        
        return configuration
    }
    
    @objc private func middleButtonTapped(_ notification: NSNotification) {
        openCamera()
    }
    
    @objc private func rightButtonTapped(_ notification: NSNotification) {
        openGallery()
    }
    
    
    private func openCamera() {
        let scannerOptions = ImageScannerOptions(scanMultipleItems: true,
                                                 allowAutoScan: false,
                                                 allowTapToFocus: false,
                                                 defaultColorRenderOption:.color)
        let scannerViewController = ScannerViewController(scanSession: nil, options: scannerOptions)
        scannerViewController.delegate = self
        scannerViewController.selectedFolder = self.selectedFolder
        scannerViewController.hidesBottomBarWhenPushed = true
        self.navigationController?.pushViewController(scannerViewController, animated: false)
    }
    
    private func openGallery() {
        var configuration = PHPickerConfiguration()
        configuration.selectionLimit = 0  // 0 means no limit
        configuration.filter = .images  // Only show images
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = self
        picker.modalPresentationStyle = .fullScreen
        present(picker, animated: true, completion: nil)
    }
    
    private func renameFile(at indexPath: IndexPath) {
        let viewModel = isSearching ? searchedViewModel[indexPath.row] : viewModels[indexPath.row]
        renameAlertController = UIAlertController(title: .renameDocument.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)
    }
    
    func moveto(file: File) {
        let foldersViewController = FoldersViewController()
        foldersViewController.selectedFolder = self.selectedFolder
        foldersViewController.movedFile = file
        foldersViewController.delegate = self
        self.present(foldersViewController, animated: true)
    }
    
    private func deleteFile(at indexPath: IndexPath) {
        let viewModel = isSearching ? searchedViewModel[indexPath.row] : viewModels[indexPath.row]
        
        if UserDefaults.standard.askOnSwipeDelete {
            let alertController = UIAlertController(title: Bundle.appName,
                                                    message: .deleteDocumentMsg.localized, preferredStyle: .alert)
            
            let okAction = UIAlertAction(title: .yesDelete.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)
            if isSearching {
                self.searchedViewModel.remove(at: indexPath.row)
            } else {
                self.viewModels.remove(at: indexPath.row)
            }
            self.tableView.deleteRows(at: [indexPath], with: .fade)
            self.fetchViewModels()
        } catch {
            delete(file: fileURL)
            self.fetchViewModels()
            return
        }
    }
    
    private func delete(file fileURL: URL) {
        do {
            try self.localFileManager?.filesManager.removeItem(at: fileURL)
            try self.localFileManager?.removeThumbnail(for: fileURL)
            self.tableView.reloadData()
        } catch {
            return
        }
    }
    
    
}

/// Tells the delegate that the user picked a still image.
extension DocumentsTableViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate {
    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 }
            if let folder = selectedFolder {
                PDFManager.createPDFDocument(from: image, localFileManager: self.localFileManager, folder: folder)
                self.fetchViewModels()
                self.tabBarController?.selectedIndex = 0
            }
        }
    }
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true) { [weak self] in
            self?.tabBarController?.selectedIndex = 0
        }
    }
}

extension DocumentsTableViewController: ImageScannerControllerDelegate {
    func imageScannerController(_ scanner: ImageScannerController, didFinishWithSession session: MultiPageScanSession) {
        if let folder = selectedFolder {
            PDFManager.savePDF(session: session, folder: folder, fileManager: localFileManager, name: "") {
                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
    }
}

extension DocumentsTableViewController: ScannerViewControllerDelegate {
    func scannerViewController(_ scannerViewController: ScannerViewController, reviewItems inSession: MultiPageScanSession) {
        let multipageScanViewController = MultiPageScanSessionViewController(scanSession: inSession)
        multipageScanViewController.delegate = self
        self.navigationController?.pushViewController(multipageScanViewController, animated: true)
        
    }
    
    func scannerViewController(_ scannerViewController: ScannerViewController, didFail withError: Error) {
        scannerViewController.dismiss(animated: true)
    }
    
    func scannerViewControllerDidCancel(_ scannerViewController: ScannerViewController) {
        scannerViewController.dismiss(animated: true)
    }
}

extension DocumentsTableViewController: AllFolderTableViewCellDelegate {
    func addFolderTapped() {
        alert(confirm: .addFolder, destructive: .cancel, message: .addFolderMessage){ folderName in
            let newFolder = AppConfigurator.Folder(name: folderName, savedName: folderName.replacingOccurrences(of: " ", with: "_"), isSelected: false)
            var currentFolders = AppConfigurator().getFolders()
            currentFolders.append(newFolder)
            if let encoded = try? JSONEncoder().encode(currentFolders) {
                UserDefaults.standard.set(encoded, forKey: "folders")
                self.AllFolderView?.refresh()
                self.dismiss(animated: true)
            }
        }
    }
    
    func cellTapped(folder: AppConfigurator.Folder) {
        selectedFolder = folder
        fetchViewModels()
    }
}

extension DocumentsTableViewController: SearchFilesViewDelegate {
    func searchfor(text: String) {
        if text.count == 0 {
            isSearching = false
            UIView.animate(withDuration: 0.5) {
                self.allFolderView_height.constant = 240
                self.AllFolderView.isHidden = false
                self.noFilesLabel.isHidden = true
            }
        } else {
            isSearching = true
            self.searchedViewModel =  self.viewModels.filter { $0.displayName.lowercased().contains(text.lowercased()) }
            if searchedViewModel.isEmpty {
                noFilesLabel.isHidden = false
            } else {
                noFilesLabel.isHidden = true
            }
        }
        tableView.reloadData()
    }
}

extension DocumentsTableViewController: PHPickerViewControllerDelegate {
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        images.removeAll()
        picker.dismiss(animated: true) {
            let dispatchGroup = DispatchGroup()
            
            for result in results {
                dispatchGroup.enter()  // Enter the group before each task
                result.itemProvider.loadObject(ofClass: UIImage.self) { (object, error) in
                    defer { dispatchGroup.leave() }  // Leave the group after each task, regardless of whether it was successful
                    if let error = error {
                        print("Error loading image: \(error)")
                    } else if let image = object as? UIImage {
                        DispatchQueue.main.async {
                            self.images.append(image)
                        }
                    }
                }
            }
            
            dispatchGroup.notify(queue: .main) {
                if !self.images.isEmpty {
                    if let folder = self.selectedFolder {
                        PDFManager.createMultiImagesPDFDocument(from: self.images, localFileManager: self.localFileManager, folder: folder)
                    }
                }
                self.fetchViewModels()
                self.tabBarController?.selectedIndex = 0
            }
        }
    }
}
extension DocumentsTableViewController: MultiPageScanSessionViewControllerDelegate {
    
    public func multiPageScanSessionViewController(_ multiPageScanSessionViewController: MultiPageScanSessionViewController,
                                                   finished session: MultiPageScanSession) {
        if let folder = selectedFolder {
            PDFManager.savePDF(session: session, folder: folder, fileManager: localFileManager, name: "") {
                self.fetchViewModels()
                self.navigationController?.popViewController(animated: true)

            }
        }
        
    }
}

extension DocumentsTableViewController: UIPageViewControllerDataSource {
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        guard let index = pageViewControllers.firstIndex(of: viewController), index > 0 else {
            return nil
        }
        return pageViewControllers[index - 1]
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        guard let index = pageViewControllers.firstIndex(of: viewController), index < pageViewControllers.count - 1 else {
            return nil
        }
        return pageViewControllers[index + 1]
    }
}

@available(iOS 16.0, *)
extension DocumentsTableViewController: DataScannerViewControllerDelegate {
    func dataScanner(_ dataScanner: DataScannerViewController, didTapOn item: RecognizedItem) {
        switch item {
        case .text(let text):
            print(text.transcript)
            let alertController = UIAlertController(title: Bundle.appName,
                                                    message: text.transcript, preferredStyle: .alert)
                        
            alertController.addAction(UIAlertAction(title: .cancel.localized, style: .cancel, handler: nil))
            self.dismiss(animated: true) {
                self.present(alertController, animated: true)
            }

        default:
            break
        }
    }
    
}

extension DocumentsTableViewController: FoldersViewControllerDelegate {
    func move(file: File, from: [AppConfigurator.Folder], to: AppConfigurator.Folder) {
        delete(file: file.fileURL)
        guard let saveUrl = localFileManager?.getFolderUrl(folder: to) else { return }
        let urlPDFtoSaveInAllDoc = saveUrl.appendingPathComponent(file.displayName)

        do {
            try file.pdfDocument?.dataRepresentation()?.write(to: urlPDFtoSaveInAllDoc)
            self.selectedFolder = to
            
            fetchViewModels()
            for (index,item) in self.AllFolderView.folders.enumerated() {
                if item.savedName == selectedFolder?.savedName {
                    self.AllFolderView.collectionView.scrollToItem(at: IndexPath(row: index, section: 0), at: .centeredHorizontally, animated: true)
                }
            }
        } catch {
            print(error.localizedDescription) // handle error
        }
    }
}