//
//  FlutterPlayerContent.swift
//  nut_player_ios
//
//  Created by Nut.Tech on 10/9/23.
//

import Foundation
import NutPlayer

struct FlutterPlayerContent: PlayerContent, Decodable {
    
    let content: ContentType
    let statistics: [PlayerStatisticRecord]
    let subtitles: [PlayerSubtitleRecord]
    
    enum CodingKeys: String, CodingKey {
        case content
        case statistics
        case subtitles
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        let statistics = try container.decode([FlutterPlayerStatisticRecord?].self, forKey: .statistics)
        self.statistics = statistics.compactMap { $0 }
        
        let subtitles = try container.decode([FlutterPlayerSubtitleRecord?].self, forKey: .subtitles)
        self.subtitles = subtitles.compactMap { $0 }
        
        let content = try container.decode(FlutterContentType.self, forKey: .content)
        guard let url = URL(string: content.url) else { throw NSError(domain: "Decode ContentType", code: 1) }
        switch content.type {
        case "auto":
            self.content = .auto(url: url)
        case "hls":
            let autoReduce = content.automaticallyReduceStalling ?? true
            self.content = .hls(url: url, autoReduceStalling: autoReduce)
        case "dash":
            self.content = .dash(url: url)
        case "mp4":
            self.content = .mp4(url: url, loop: content.isLoop ?? false)
        default:
            self.content = .raw(data: Data())
        }
    }
}

struct FlutterContentType: Decodable {
    let type: String
    let url: String
    let automaticallyReduceStalling: Bool?
    let isLoop: Bool?
    
    enum CodingKeys: String, CodingKey {
        case type
        case url
        case automaticallyReduceStalling
        case isLoop
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.type = try container.decode(String.self, forKey: .type)
        self.url = try container.decode(String.self, forKey: .url)
        self.automaticallyReduceStalling = try container.decodeIfPresent(Bool.self, forKey: .automaticallyReduceStalling)
        self.isLoop = try container.decodeIfPresent(Bool.self, forKey: .isLoop)
    }
}

struct FlutterPlayerStatisticRecord: PlayerStatisticRecord, Decodable {
    
    let name: String
    let urlTemplate: String
    let start: TimeInterval
    let delay: TimeInterval
    let count: Int
    let method: HTTPMethod
    let body: String?
    
    enum CodingKeys: String, CodingKey {
        case name
        case urlTemplate
        case start
        case delay
        case count
        case method
        case body
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.name = try container.decode(String.self, forKey: .name)
        self.urlTemplate = try container.decode(String.self, forKey: .urlTemplate)
        self.start = try container.decode(TimeInterval.self, forKey: .start)
        self.delay = try container.decode(TimeInterval.self, forKey: .delay)
        self.count = try container.decode(Int.self, forKey: .count)
        let method = try container.decode(String.self, forKey: .method)
        self.method = method.lowercased() == "get" ? .get : .post
        let body = try? container.decode(String.self, forKey: .name)
        if let value = body {
            self.body = value.isEmpty ? nil : value
        } else {
            self.body = nil
        }
        
    }
}

struct FlutterPlayerSubtitleRecord: PlayerSubtitleRecord, Decodable {
    let title: String
    let type: SubtitleType
    let url: String
    let language: String
    
    enum CodingKeys: String, CodingKey {
        case title
        case type
        case url
        case language
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.title = try container.decode(String.self, forKey: .title)
        self.url = try container.decode(String.self, forKey: .url)
        self.language = try container.decode(String.self, forKey: .language)
        let type = try container.decode(String.self, forKey: .type)
        self.type = .SRT
    }
}
