
// TODO: Move to settings?
extension HeaderElement {

    static let swiperCssFileOrder = 41

    static let defaultCssFileOrder = 42

    static let audioPlayerCssOrder = 43

    static let imageCompareCssOrder = 44
}

enum HeaderElement {

    /// Order: 10-19
    case icon(file: FileResource, size: Int, rel: String)

    /// Order: From 40-99, lower numbers appear first
    case css(file: FileResource, order: Int)

    /// Order: 20-29
    case js(file: FileResource, defer: Bool)

    /// Order: 30-39
    case jsModule(FileResource)

    case author(String)

    case title(String)

    case description(String)

    case ogTitle(String)

    case ogDescription(String)

    case ogImage(String)

    case ogUrl(String)

    case charset

    case viewport

    case robots

    case manifest(FileResource)

    case style(String)

    var order: Int {
        switch self {
        case .charset: 1
        case .robots: 2
        case .viewport: 3
        case .manifest: 4
        case .icon: 10
        case .css(_, let order): order
        case .js: 20
        case .jsModule: 30
        case .author: 100
        case .title: 101
        case .description: 102
        case .ogTitle: 103
        case .ogDescription: 104
        case .ogImage: 105
        case .ogUrl: 106
        case .style: 200
        }
    }

    var requiredFile: FileResource? {
        switch self {
        case .icon(let file, _, _):
            return file
        case .css(let file, _):
            return file
        case .js(let file, _):
            return file
        case .jsModule(let file):
            return file
        case .manifest(let file):
            return file
        default:
            return nil
        }
    }
}

extension HeaderElement: Hashable {
    
}

extension HeaderElement: Comparable {

    static func < (lhs: HeaderElement, rhs: HeaderElement) -> Bool {
        guard lhs.order == rhs.order else {
            return lhs.order < rhs.order
        }
        return lhs.content < rhs.content
    }
}

extension HeaderElement {

    var content: String {
        switch self {
        case .icon(let file, let size, let rel):
            return "<link rel='\(rel)' sizes='\(size)x\(size)' href='\(file.absoluteUrl)'>"
        case .css(let file, _):
            return "<link rel='stylesheet' href='\(file.absoluteUrl)' />"
        case .js(let file, let deferred):
            let deferText = deferred ? " defer" : ""
            return "<script src='\(file.absoluteUrl)'\(deferText)></script>"
        case .jsModule(let file):
            return "<script type='module' src='\(file.absoluteUrl)'></script>"
        case .author(let author):
            return "<meta name='author' content='\(author)'>"
        case .title(let title):
            return "<title>\(title)</title>"
        case .description(let description):
            return "<meta name='description' content=\"\(description)\">"
        case .ogTitle(let title):
            return "<meta property='og:title' content='\(title)'>"
        case .ogDescription(let description):
            return "<meta property='og:description' content='\(description)'>"
        case .ogImage(let image):
            return "<meta property='og:image' content='\(image)'>"
        case .ogUrl(let url):
            return "<meta property='og:url' content='\(url)'>"
        case .charset:
            return "<meta charset='utf-8' />"
        case .viewport:
            return "<meta name='viewport' content='width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1' />"
        case .robots:
            return "<meta name='robots' content='noindex'>"
        case .manifest(let file):
            return "<link rel='manifest' href='\(file.absoluteUrl)'>"
        case .style(let style):
            return "<style>\(style)</style>"
        }
    }
}

extension HeaderElement: CustomStringConvertible {

    var description: String {
        switch self {
        case .icon(let file, _, _):
            return file.description
        case .css(let file, _):
            return file.description
        case .js(let file, let deferred):
            return file.description + (deferred ? " (deferred)" : "")
        case .jsModule(let file):
            return file.description
        case .author:
            return "author"
        case .title:
            return "title"
        case .description:
            return "description"
        case .ogTitle:
            return "og:title"
        case .ogDescription:
            return "og:description"
        case .ogImage:
            return "og:image"
        case .ogUrl:
            return "og:url"
        case .charset:
            return "charset"
        case .viewport:
            return "viewport"
        case .robots:
            return "robots"
        case .manifest:
            return "manifest"
        case .style:
            return "style"
        }
    }
}
