import SwiftUI
import SFSafeSymbols

struct GenerationContentView: View {

    @Environment(\.language)
    private var language

    @EnvironmentObject
    private var content: Content

    @EnvironmentObject
    private var selection: SelectedContent

    @Environment(\.dismiss)
    private var dismiss

    var draftPages: Set<Page> {
        Set(content.pages.filter { $0.isDraft })
    }

    var draftPosts: Set<Post> {
        Set(content.posts.filter { $0.isDraft })
    }

    var body: some View {
        VStack(alignment: .leading) {
            Text("Website Generation")
                .font(.largeTitle)
                .bold()
            Text("Regenerate the website and monitor the output")
                .foregroundStyle(.secondary)
                .padding(.bottom, 30)

            HStack {
                Button {
                    if content.isGeneratingWebsite {
                        content.endCurrentGeneration()
                    } else {
                        content.generateWebsiteInAllLanguages()
                    }
                } label: {
                    Text(content.isGeneratingWebsite ? "Cancel" : "Generate")
                }
                .disabled(content.isGeneratingWebsite != content.shouldGenerateWebsite)
                if content.isGeneratingWebsite {
                    ProgressView()
                        .progressViewStyle(.circular)
                        .scaleEffect(0.6)
                        .frame(height: 16)
                }
                Spacer()
            }
            Text(content.generationStatus)
                .padding(.vertical, 5)
            GenerationStringIssuesView(
                text: "output files",
                statusWhenNonEmpty: .nominal,
                items: content.results.outputFiles)
            GenerationResultsIssueView(
                text: "\(content.results.imagesToGenerate.count) images",
                status: .nominal,
                items: { [] })
            GenerationResultsIssueView(
                text: "\(content.results.resultCount) items processed",
                status: .nominal,
                items: { [] })
            GenerationStringIssuesView(
                text: "external links",
                statusWhenNonEmpty: .nominal,
                items: content.results.externalLinks)
            GenerationStringIssuesView(
                text: "required files",
                statusWhenNonEmpty: .nominal,
                items: content.results.requiredFiles) { $0.identifier }
            GenerationStringIssuesView(
                text: "external files",
                statusWhenNonEmpty: .nominal,
                items: content.results.externalFiles) { $0.identifier }
            GenerationIssuesView(
                text: "empty pages",
                statusWhenNonEmpty: .warning,
                items: $content.results.emptyPages) { pageId in
                    HStack {
                        Text("\(pageId.pageId) (\(pageId.language.description))")
                        Spacer()
                        Button("Show") {
                            show(page: pageId.pageId,
                                 language: pageId.language)
                        }
                    }
                }

            GenerationIssuesActionView(
                title: "draft pages",
                statusWhenNonEmpty: .warning,
                items: draftPages,
                buttonText: "Show",
                itemText: { $0.identifier },
                action: { show($0) })
            GenerationIssuesActionView(
                title: "draft posts",
                statusWhenNonEmpty: .warning,
                items: draftPosts,
                buttonText: "Show",
                itemText: { $0.identifier },
                action: { show($0) })
            GenerationIssuesView(
                text: "additional output files",
                statusWhenNonEmpty: .warning,
                items: $content.results.unusedFilesInOutput) { filePath in
                    HStack {
                        Text(filePath)
                        Spacer()
                        Button("Delete", action: { delete(unusedFile: filePath) })
                    }
                }
            GenerationStringIssuesView(
                text: "missing output files",
                statusWhenNonEmpty: .warning,
                items: content.results.requiredOutputFiles)
            GenerationStringIssuesView(
                text: "inaccessible files",
                items: content.results.inaccessibleFiles) { $0.identifier }
            GenerationStringIssuesView(
                text: "unparsable files",
                items: content.results.unparsableFiles) { $0.identifier }
            GenerationStringIssuesView(
                text: "unsaved output files",
                items: content.results.unsavedOutputFiles)
            GenerationStringIssuesView(
                text: "failed image generations",
                items: content.results.failedImages) { $0.outputPath }
            GenerationStringIssuesView(
                text: "missing files",
                items: content.results.missingFiles)
            GenerationStringIssuesView(
                text: "missing tags",
                items: content.results.missingTags)
            GenerationStringIssuesView(
                text: "missing pages",
                items: content.results.missingPages) { pageId in
                    let sources = content.results.sources(forMissingPage: pageId)
                        .map { "\($0.page): \($0.source)"}
                        .joined(separator: ", ")

                    return "\(pageId) (\(sources))"
                }
            GenerationStringIssuesView(
                text: "invalid commands",
                items: content.results.invalidCommands)
            GenerationStringIssuesView(
                text: "invalid blocks",
                items: content.results.invalidBlocks)
            GenerationStringIssuesView(
                text: "warnings",
                statusWhenNonEmpty: .warning,
                items: content.results.warnings)
            HorizontalCenter {
                Button(action: { dismiss() }) {
                    Text("Close")
                }
            }
        }.padding()
    }

    private func delete(unusedFile: String) {
        guard content.storage.deleteInOutputFolder(unusedFile) else {
            return
        }
        content.results.unusedFilesInOutput.remove(unusedFile)
    }

    private func show(page pageId: String, language: ContentLanguage? = nil) {
        guard let page = content.page(pageId) else {
            return
        }
        show(page, language: language)
    }

    private func show(_ page: Page, language: ContentLanguage? = nil) {
        selection.page = page
        if let language {
            selection.language = language
        }
        selection.tab = .pages
        dismiss()
    }

    private func show(_ post: Post, language: ContentLanguage? = nil) {
        selection.post = post
        if let language {
            selection.language = language
        }
        selection.tab = .posts
        dismiss()
    }
}

#Preview {
    GenerationContentView()
        .environmentObject(Content.mock)
        .padding()
}
