import SwiftUI
import SFSafeSymbols
import HighlightedTextEditor

enum PageContentSaveStatus {
    case isSaved
    case failedToSave
    case needsSave
    case notLoaded
    case isSaving

    var symbol: SFSymbol {
        switch self {
        case .notLoaded:
            return .questionmarkSquareDashed
        case .isSaved:
            return .checkmarkCircleFill
        case .needsSave, .isSaving:
            return .hourglassCircleFill
        case .failedToSave:
            return .exclamationmarkTriangleFill
        }
    }

    var color: Color {
        switch self {
        case .isSaved, .notLoaded:
            return .green
        case .needsSave, .isSaving:
            return .yellow
        case .failedToSave:
            return .red
        }
    }
}

struct LocalizedPageContentView: View {

    @EnvironmentObject
    var content: Content

    @ObservedObject
    var page: Page

    let language: ContentLanguage

    @State
    private var pageContent: String = ""

    @State
    private var generationResults: PageGenerationResults?

    @State
    private var saveState: PageContentSaveStatus = .notLoaded

    @State
    private var lastSave: Date = .now

    @State
    private var lastModification: Date = .now

    var body: some View {
        VStack(alignment: .leading) {
            HStack {
                Image(systemSymbol: saveState.symbol)
                    .foregroundStyle(saveState.color)
                if let generationResults {
                    PageContentResultsView(results: generationResults)
                }
                let linkingPosts = content.posts.filter { $0.linkedPage == page }
                TextWithPopup(
                    symbol: .ipadAndArrowForward,
                    title: "Post linking to page",
                    text: "\(linkingPosts.count) linking posts",
                    items: linkingPosts.map { $0.title(in: language) })
            }.foregroundStyle(.secondary)
            InsertableItemsView()
            HighlightedTextEditor(
                text: $pageContent,
                highlightRules: .markdown)
            .onChange(of: pageContent) {
                didChangeContent()
            }
        }
        .onAppear(perform: loadContent)
        .onDisappear { saveContentIfNeeded(isFinalSave: true) }
    }

    private func didChangeContent() {
        if saveState == .notLoaded {
            // Content was changed due to loading
            saveState = .isSaved
            return
        }
        saveState = .needsSave
        lastModification = .now

        // Wait a few seconds for a save, to allow additional changes
        // Reduces the number of saves
        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(10)) {
            self.saveContentIfNeeded()
        }
    }

    private func loadContent() {
        let language = language
        guard page.localized(in: language).hasContent else {
            pageContent = "New file"
            return
        }
        guard let content = page.pageContent(in: language) else {
            print("Failed to load page content")
            pageContent = "Failed to load"
            return
        }
        guard content != "" else {
            pageContent = "New file"
            return
        }
        pageContent = content
        checkContent()
    }

    private func saveContentIfNeeded(isFinalSave: Bool = false) {
        switch saveState {
        case .isSaved, .notLoaded, .isSaving:
            return
        default:
            break
        }

        if !isFinalSave, Date.now.timeIntervalSince(lastModification) < 10 {
            // Additional modification made
            // Wait for next scheduled invocation of saveIfNeeded()
            // if the overall unsaved time is not too long
            if Date.now.timeIntervalSince(lastSave) < 60 {
                //print("Waiting while modifying")
                return
            }
            print("Saving content after 30 seconds of modifications")
        }
        saveState = .isSaving
        saveUnconditionally()
    }

    private func saveUnconditionally() {
        guard pageContent != "New file", pageContent != "" else {
            guard page.removeContent(in: language) else {
                print("Failed to remove empty content from disk")
                saveState = .failedToSave
                return
            }
            saveState = .notLoaded
            generationResults = nil
            return
        }

        guard page.save(pageContent: pageContent, in: language) else {
            print("Failed to save content")
            saveState = .failedToSave
            return
        }

        saveState = .isSaved
        lastSave = .now
        checkContent()
    }

    private func checkContent() {
        guard !self.content.isGeneratingWebsite else {
            return
        }
        self.content.check(content: pageContent, of: page, for: language) {
            self.generationResults = $0
        }
    }
}
