//
//  HtmlGenerator.swift
//  Padel Tournament
//
//  Created by Razmig Sarkissian on 23/10/2023.
//

import Foundation
import UIKit
import WebKit
import PDFKit

class HtmlGenerator: ObservableObject {
    
    init(tournament: Tournament) {
        self.tournament = tournament
    }
    
    let tournament: Tournament
    @Published var zoomLevel: CGFloat? = 2.0
    @Published var includeBracket: Bool = true
    @Published var includeGroupStage: Bool = true
    @Published var includeLoserBracket: Bool = false
    @Published var displayHeads: Bool = false
    @Published var groupStageIsReady: Bool = false
    @Published var displayRank: Bool = false
    private var pdfDocument: PDFDocument = PDFDocument()
    private var rects: [CGRect] = []
    private var completionHandler: ((Result<Bool, Error>) -> ())?
    @Published var width: CGFloat = 0
    @Published var height: CGFloat = 0
    private var webView: WKWebView = WKWebView()
    private var groupStageDone: Int = 0
    
    var estimatedPageCount: Int {
        if let zoomLevel {
            let pageSize = CGSize(width: 595 * (1 + zoomLevel), height: 812 * (1 + zoomLevel))
            let numberOfPageInWidth = Int(width / pageSize.width) + 1
            let numberOfPageInHeight = Int(height / pageSize.height) + 1
            return numberOfPageInWidth * numberOfPageInHeight
        } else {
            return 1
        }
    }
    
    func preparePDF(completionHandler: @escaping ((Result<Bool, Error>) -> ())) {
        self.completionHandler = completionHandler
    }
    
    func generateWebView(webView: WKWebView) {
        self.webView = webView
        self.webView.evaluateJavaScript("document.readyState", completionHandler: { (complete, error) in
            if complete != nil {
                self.webView.evaluateJavaScript("document.documentElement.scrollHeight", completionHandler: { (height, error) in
                    self.height = height as! CGFloat
                })
                self.webView.evaluateJavaScript("document.documentElement.scrollWidth", completionHandler: { (width, error) in
                    self.width = width as! CGFloat
                })
            }
            
            if self.completionHandler != nil {
                self.buildPDF()
            }
        })
    }
    
    func generateGroupStage(webView: WKWebView) {
        webView.evaluateJavaScript("document.readyState", completionHandler: { (complete, error) in
            if complete != nil {
                webView.evaluateJavaScript("document.documentElement.scrollHeight", completionHandler: { (height, error) in
                    let height = height as! CGFloat
                    webView.evaluateJavaScript("document.documentElement.scrollWidth", completionHandler: { (width, error) in
                        let width = width as! CGFloat
                        
                        print("bracket", width, height)
                        let config = WKPDFConfiguration()
                        config.rect = CGRect(origin: .zero, size: CGSize(width: Int(width), height: Int(width)))
                        webView.createPDF(configuration: config){ result in
                            switch result{
                            case .success(let data):
                                let newPage = PDFDocument(data: data)!
                                let page = newPage.page(at: 0)!
                                let copiedPage = page.copy() as! PDFPage
                                self.pdfDocument.insert(copiedPage, at: self.pdfDocument.pageCount)
                                
                                DispatchQueue.main.async {
                                    self.groupStageDone += 1
                                    if self.groupStageDone == self.tournament.groupStages().count {
                                        self.groupStageIsReady = true
                                        self.completionHandler?(.success(self.savePDF()))
                                    }
                                }
                            case .failure(let error):
                                self.completionHandler?(.failure(error))
                            }
                        }

                    })
                })
            }
        })

    }
    
    func buildPDF() {
        groupStageDone = 0
        groupStageIsReady = false
        pdfDocument = PDFDocument()
        rects.removeAll()
        try? FileManager.default.removeItem(at: pdfURL!)
        print("buildPDF", width, height, zoomLevel ?? 0)
        if let zoomLevel {
            let pageSize = CGSize(width: 595 * (1 + zoomLevel), height: 812 * (1 + zoomLevel))
            let numberOfPageInWidth = Int(width / pageSize.width) + 1
            let numberOfPageInHeight = Int(height / pageSize.height) + 1
            for w in 0..<numberOfPageInWidth {
                for h in 0..<numberOfPageInHeight {
                    let rect = CGRect(x: CGFloat(w) * pageSize.width, y: CGFloat(h) * pageSize.height, width: pageSize.width, height: pageSize.height)
                    rects.append(rect)
                }
            }
        } else {
            rects = [CGRect(origin: .zero, size: CGSize(width: Int(width), height: Int(height)))]
        }
        
        if includeBracket {
            createPage()
        } else {
            DispatchQueue.main.async {
                self.completionHandler?(.success(true))
            }
        }
    }
    
    func createPage() {
        let config = WKPDFConfiguration()
        config.rect = rects[pdfDocument.pageCount]
        webView.createPDF(configuration: config){ result in
            switch result{
            case .success(let data):
                let newPage = PDFDocument(data: data)!
                let page = newPage.page(at: 0)!
                let copiedPage = page.copy() as! PDFPage
                self.pdfDocument.insert(copiedPage, at: self.pdfDocument.pageCount)
                if self.pdfDocument.pageCount < self.rects.count {
                    self.createPage()
                } else {
                    self.completionHandler?(.success(self.savePDF()))
                }
            case .failure(let error):
                self.completionHandler?(.failure(error))
            }
        }
    }

    func generateHtml() -> String {
        //HtmlService.groupstage(bracket: tournament.orderedBrackets.first!).html()
        HtmlService.template(tournament: tournament).html(headName: displayHeads, withRank: displayRank, withScore: false)
    }
    
    var pdfURL: URL? {
        guard let pdfFolderURL = getFilePath() else {
            return nil
        }
        let date = tournament.startDate
        let stringDate = date.formatted(.iso8601
            .year()
            .month()
            .day()
            .dateSeparator(.dash))

        let name = tournament.tournamentLevel.localizedLabel() + "-" + tournament.tournamentCategory.importingRawValue
        return pdfFolderURL.appendingPathComponent(stringDate + "-" + name + ".pdf")
    }
    
    func savePDF() -> Bool {
        pdfDocument.write(to: pdfURL!)
    }
    
    var isReady: Bool {
        FileManager.default.fileExists(atPath: pdfURL!.path())
    }
    
    func getFilePath() -> URL? {
        if FileManager.default.fileExists(atPath: pdfFolderURL.path) {
            return pdfFolderURL
        } else {
            do {
                try FileManager.default.createDirectory(at: pdfFolderURL, withIntermediateDirectories: true, attributes: nil)
                return pdfFolderURL
            } catch {
                print("getFilePath", error.localizedDescription)
                return nil
            }
        }
    }
    
    var pdfFolderURL: URL {
        let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
        return URL(fileURLWithPath: documentsPath.appending("/pdfs"))
    }
}
