import Foundation

final class Page: Item {

    /**
     The external link this page points to.

     If this value is not `nil`, then the page has no content
     and many other features are disabled.
     */
    @Published
    var externalLink: String?

    @Published
    var isDraft: Bool

    @Published
    var createdDate: Date

    @Published
    var hideDate: Bool

    @Published
    var startDate: Date

    @Published
    var hasEndDate: Bool

    @Published
    var endDate: Date

    @Published
    var german: LocalizedPage

    @Published
    var english: LocalizedPage

    @Published
    var tags: [Tag]

    /**
     Additional files to copy, because the page content references them
     */
    @Published
    var requiredFiles: [FileResource]

    init(content: Content,
         id: String,
         externalLink: String?,
         isDraft: Bool,
         createdDate: Date,
         hideDate: Bool,
         startDate: Date,
         endDate: Date?,
         german: LocalizedPage,
         english: LocalizedPage,
         tags: [Tag],
         requiredFiles: [FileResource]) {
        self.externalLink = externalLink
        self.isDraft = isDraft
        self.createdDate = createdDate
        self.hideDate = hideDate
        self.startDate = startDate
        self.hasEndDate = endDate != nil
        self.endDate = endDate ?? startDate
        self.german = german
        self.english = english
        self.tags = tags
        self.requiredFiles = requiredFiles

        super.init(content: content, id: id)
    }

    func isValid(id: String) -> Bool {
        !id.isEmpty &&
        content.isValidIdForTagOrPageOrPost(id) &&
        content.isNewIdForPage(id)
    }

    @discardableResult
    func update(id newId: String) -> Bool {
        guard content.storage.move(page: id, to: newId) else {
            print("Failed to move files of page \(id)")
            return false
        }
        id = newId
        return true
    }

    var isExternalUrl: Bool {
        externalLink != nil
    }

    // MARK: Tags

    /**
     Check if a tag is associated with this page
     */
    func contains(_ tag: Tag) -> Bool {
        tags.contains(tag)
    }

    func toggle(_ tag: Tag) {
        guard let index = tags.firstIndex(of: tag) else {
            tags.append(tag)
            return
        }
        tags.remove(at: index)
    }

    func remove(_ tag: Tag) {
        tags.remove(tag)
    }

    func associate(_ tag: Tag) {
        guard !tags.contains(tag) else {
            return
        }
        tags.append(tag)
    }

    // MARK: Paths

    override func absoluteUrl(in language: ContentLanguage) -> String {
        if let url = externalLink {
            return url
        }
        // TODO: Record link to trace connections between pages
        return makeCleanAbsolutePath(internalPath(for: language))
    }

    override func title(in language: ContentLanguage) -> String {
        localized(in: language).title
    }

    func filePathRelativeToOutputFolder(for language: ContentLanguage) -> String {
        makeCleanRelativePath(internalPath(for: language))
    }

    private func internalPath(for language: ContentLanguage) -> String {
        content.settings.paths.pagesOutputFolderPath + "/" + localized(in: language).urlString
    }

    override var itemType: ItemType {
        .page(self)
    }

    func contains(urlComponent: String) -> Bool {
        english.urlString == urlComponent || german.urlString == urlComponent
    }

    func pageContent(in language: ContentLanguage) -> String? {
        content.storage.pageContent(for: id, language: language)
    }

    func hasContent(in language: ContentLanguage) -> Bool {
        content.storage.hasPageContent(for: id, language: language)
    }
}

extension Page: DateItem {

}

extension Page: LocalizedItem {
    
}
