//
//  Attachment.swift
//  Pachyderm
//
//  Created by Shadowfacts on 9/9/18.
//  Copyright © 2018 Shadowfacts. All rights reserved.
//

import Foundation

public struct Attachment: Codable, Sendable {
    public let id: String
    public let kind: Kind
    public let url: URL
    public let remoteURL: URL?
    public let previewURL: URL?
    public let meta: Metadata?
    public let description: String?
    public let blurHash: String?
    
    public static func update(_ attachment: Attachment, focus: (Float, Float)?, description: String?) -> Request<Attachment> {
        return Request<Attachment>(method: .put, path: "/api/v1/media/\(attachment.id)", body: FormDataBody([
                "description" => (description ?? attachment.description),
                "focus" => focus
            ], nil))
    }
    
    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.id = try container.decode(String.self, forKey: .id)
        self.kind = try container.decode(Kind.self, forKey: .kind)
        self.url = try container.decode(URL.self, forKey: .url)
        self.previewURL = try? container.decode(URL?.self, forKey: .previewURL)
        self.remoteURL = try? container.decode(URL?.self, forKey: .remoteURL)
        self.meta = try? container.decode(Metadata?.self, forKey: .meta)
        self.description = try? container.decode(String?.self, forKey: .description)
        self.blurHash = try? container.decode(String?.self, forKey: .blurHash)
    }
    
    private enum CodingKeys: String, CodingKey {
        case id
        case kind = "type"
        case url
        case remoteURL = "remote_url"
        case previewURL = "preview_url"
        case meta
        case description
        case blurHash = "blurhash"
    }
}

extension Attachment {
    public enum Kind: String, Codable, Sendable {
        case image
        case video
        case gifv
        case audio
        case unknown
        
        public init(from decoder: Decoder) throws {
            let container = try decoder.singleValueContainer()
            switch try container.decode(String.self) {
            // gotosocial uses "gif" for gif images
            case "image", "gif":
                self = .image
            case "video":
                self = .video
            case "gifv":
                self = .gifv
            case "audio":
                self = .audio
            default:
                self = .unknown
            }
        }
    }
}

extension Attachment {
    public struct Metadata: Codable, Sendable {
        public let length: String?
        public let duration: Float?
        public let audioEncoding: String?
        public let audioBitrate: String?
        public let audioChannels: String?
        public let fps: Float?
        public let width: Int?
        public let height: Int?
        public let size: String?
        public let aspect: Float?
        
        public let small: ImageMetadata?
        public let original: ImageMetadata?
        
        private enum CodingKeys: String, CodingKey {
            case length
            case duration
            case audioEncoding = "audio_encode"
            case audioBitrate = "audio_bitrate"
            case audioChannels = "audio_channels"
            case fps
            case width
            case height
            case size
            case aspect
            case small
            case original
        }
    }
    
    public struct ImageMetadata: Codable, Sendable {
        public let width: Int?
        public let height: Int?
        public let size: String?
        public let aspect: Float?
        
        private enum CodingKeys: String, CodingKey {
            case width
            case height
            case size
            case aspect
        }
    }
}
