
final class LoadingContext {

    let content: Content

    var files: [String: FileResource] = [:]

    var pages: [String : Page] = [:]

    var tags: [String : Tag] = [:]

    var posts: [String : Post] = [:]

    var errors: Set<String> = []

    var tagOverview: TagOverview?

    var settings: Settings?

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

    func results() -> LoadingResult {
        .init(
            settings: settings ?? .default,
            posts: posts.values.sortedByStartDateAndId(),
            pages: pages.values.sortedByStartDateAndId(),
            tags: tags.values.sorted(),
            files: files.values.sorted { $0.identifier },
            tagOverview: tagOverview,
            errors: errors.sorted().map { StorageError(message: $0) })
    }

    func error(_ message: String) {
        errors.insert(message)
    }

    func post(_ postId: String) -> Post? {
        if let post = posts[postId] {
            return post
        }
        error("Missing post \(postId)")
        return nil
    }

    func tag(_ tagId: String) -> Tag? {
        if let tag = tags[tagId] {
            return tag
        }
        error("Missing tag \(tagId)")
        return nil
    }

    func page(_ pageId: String) -> Page? {
        if let page = pages[pageId] {
            return page
        }
        error("Missing page \(pageId)")
        return nil
    }

    func file(_ fileId: String) -> FileResource? {
        if let file = files[fileId] {
            return file
        }
        error("Missing file \(fileId)")
        return nil
    }

    func image(_ imageId: String) -> FileResource? {
        guard let image = file(imageId) else {
            return nil
        }
        if image.type.isImage {
            return image
        }
        error("Image \(imageId) is not an image")
        return nil
    }

    func postMedia(_ imageId: String) -> FileResource? {
        guard let image = file(imageId) else {
            return nil
        }
        if image.type.isImage || image.type.isVideo {
            return image
        }
        error("Post Media \(imageId) is not an image or video")
        return nil
    }

    func item(itemId: ItemId) -> Item? {
        switch itemId.type {
        case .post:
            guard let id = itemId.id else {
                error("Missing post id in itemId")
                return nil
            }
            return post(id)
        case .page:
            guard let id = itemId.id else {
                error("Missing page id in itemId")
                return nil
            }
            return page(id)
        case .tag:
            guard let id = itemId.id else {
                error("Missing tag id in itemId")
                return nil
            }
            return tag(id)
        case .tagOverview:
            guard let tagOverview else {
                error("Missing tag overview")
                return nil
            }
            return tagOverview
        case .file:
            guard let id = itemId.id else {
                error("Missing file id in itemId")
                return nil
            }
            return file(id)
        }
    }
}
