import Foundation

final class PageIssueChecker: ObservableObject {

    @Published
    var isCheckingPages: Bool = false

    @Published
    var issues: Set<PageIssue> = []

    init() {
        
    }

    func check(pages: [Page], clearListBeforeStart: Bool = true) {
        guard !isCheckingPages else {
            return
        }
        isCheckingPages = true
        if clearListBeforeStart {
            issues = []
        }
        DispatchQueue.global(qos: .userInitiated).async {
            for language in ContentLanguage.allCases {
                self.check(pages: pages, in: language)
            }
            DispatchQueue.main.async {
                self.isCheckingPages = false
            }
        }
    }

    private func check(pages: [Page], in language: ContentLanguage) {
        for page in pages {
            analyze(page: page, in: language)
        }
    }

    func check(page: Page, in language: ContentLanguage) {
        guard !isCheckingPages else {
            return
        }
        isCheckingPages = true
        DispatchQueue.global(qos: .userInitiated).async {
            self.analyze(page: page, in: language)
            DispatchQueue.main.async {
                self.isCheckingPages = false
            }
        }
    }

    private func analyze(page: Page, in language: ContentLanguage) {
        let results = page.content.results.makeResults(for: page, in: language)
        let parser = PageContentParser(content: page.content, language: language, results: results)

        let hasPreviousIssues = issues.contains { $0.page == page && $0.language == language }
        let pageIssues: [PageIssue]
        if let rawPageContent = page.content.storage.pageContent(for: page.id, language: language) {
            _ = parser.generatePage(from: rawPageContent)
            pageIssues = []
        } else {
            let message = GenerationAnomaly.failedToLoadContent
            let error = PageIssue(page: page, language: language, message: message)
            pageIssues = [error]
        }
        guard hasPreviousIssues || !pageIssues.isEmpty else {
            return
        }
        update(issues: pageIssues, for: page, in: language)
    }

    private func update(issues: [PageIssue], for page: Page, in language: ContentLanguage) {
        let newIssues = self.issues
            .filter { $0.page != page || $0.language != language }
            .union(issues)

        DispatchQueue.main.async {
            self.issues = newIssues
        }
    }

}
