import Foundation

final class PageGenerator {

    private let content: Content

    init(content: Content) {
        self.content = content
    }

    private func makeHeaders(requiredItems: Set<KnownHeaderElement>, results: PageGenerationResults) -> Set<HeaderElement> {
        var result = content.contentPageHeaders
        for item in requiredItems {
            guard let header = item.header(content: content) else {
                results.warning("Header \(item) not configured in settings")
                continue
            }
            result.insert(header)
        }
        return result
    }

    private func makeEmptyPageContent(in language: ContentLanguage) -> String {
        let settings = content.settings.pages.localized(in: language)
        return ContentBox(
            title: settings.emptyPageTitle,
            text: settings.emptyPageText).content
    }

    func generate(page: Page, language: ContentLanguage, results: PageGenerationResults, pageUrl: String) -> String? {
        let contentGenerator = PageContentParser(
            content: content,
            language: language, results: results)

        let rawPageContent: String
        if let existing = content.storage.pageContent(for: page.identifier, language: language) {
            rawPageContent = existing
        } else {
            rawPageContent = makeEmptyPageContent(in: language)
            // Only mark non-draft pages as empty
            if !page.isDraft {
                results.markPageAsEmpty()
            }
        }

        let pageContent = contentGenerator.generatePage(from: rawPageContent)

        let localized = page.localized(in: language)

        let tags: [FeedEntryData.Tag] = page.tags.map { tag in
            .init(name: tag.localized(in: language).name,
                  url: tag.absoluteUrl(in: language))
        }

        let requiredHeaders = DispatchQueue.main.sync { results.requiredHeaders }
        let headers = makeHeaders(requiredItems: requiredHeaders, results: results)
        results.require(files: headers.compactMap { $0.requiredFile })

        let iconUrl = content.settings.navigation.localized(in: language).rootUrl
        let languageUrl = page.absoluteUrl(in: language.next)
        let languageButton = NavigationBar.Link(
            text: language.next.rawValue,
            url: languageUrl)

        let imageUrl = localized.linkPreview.image?.linkPreviewImage(results: results)
        let icons = DispatchQueue.main.sync { results.requiredIcons }

        let pageHeader = PageHeader(
            language: language,
            title: localized.linkPreview.title ?? localized.title,
            description: localized.linkPreview.description,
            image: imageUrl,
            pageUrl: pageUrl,
            iconUrl: iconUrl,
            languageButton: languageButton,
            links: content.navigationBar(in: language),
            headers: headers,
            icons: icons)

        let footers = DispatchQueue.main.sync { results.requiredFooters }

        let fullPage = GenericPage(
            header: pageHeader,
            additionalFooter: footers.sorted().joined()) { content in
                content += "<article>"
                if !localized.hideTitle {
                    if !page.hideDate {
                        content += "<h3>\(page.dateText(in: language))</h3>"
                    }
                    content += "<h1>\(localized.title)</h1>"
                    content += TagList(tags: tags).content
                }
                content += pageContent
                content += "</article>"
            }

        return fullPage.content
    }
}
