//
//  FilterV2.swift
//  Pachyderm
//
//  Created by Shadowfacts on 12/2/22.
//

import Foundation

public struct FilterV2: Decodable, Sendable {
    public let id: String
    public let title: String
    public let context: [FilterV1.Context]
    public let expiresAt: Date?
    public let action: Action
    public let keywords: [Keyword]
    
    public static func update(
        _ filterID: String,
        title: String,
        context: [FilterV1.Context],
        expiresIn: TimeInterval?,
        action: Action,
        keywords keywordUpdates: [KeywordUpdate]
    ) -> Request<FilterV2> {
        var keywordsParams = [Parameter]()
        for (index, update) in keywordUpdates.enumerated() {
            switch update {
            case .update(id: let id, keyword: let keyword, wholeWord: let wholeWord):
                keywordsParams.append("keywords_attributes[\(index)][id]" => id)
                keywordsParams.append("keywords_attributes[\(index)][keyword]" => keyword)
                keywordsParams.append("keywords_attributes[\(index)][whole_word]" => wholeWord)
            case .add(keyword: let keyword, wholeWord: let wholeWord):
                keywordsParams.append("keywords_attributes[\(index)][keyword]" => keyword)
                keywordsParams.append("keywords_attributes[\(index)][whole_word]" => wholeWord)
            case .destroy(id: let id):
                keywordsParams.append("keywords_attributes[\(index)][id]" => id)
                keywordsParams.append("keywords_attributes[\(index)][_destroy]" => true)
            }
        }
        return Request(method: .put, path: "/api/v2/filters/\(filterID)", body: ParametersBody([
            "title" => title,
            "expires_in" => expiresIn,
            "filter_action" => action.rawValue,
        ] + "context" => context.contextStrings + keywordsParams))
    }
    
    public static func create(
        title: String,
        context: [FilterV1.Context],
        expiresIn: TimeInterval?,
        action: Action,
        keywords keywordUpdates: [KeywordUpdate]
    ) -> Request<FilterV2> {
        var keywordsParams = [Parameter]()
        for (index, update) in keywordUpdates.enumerated() {
            switch update {
            case .add(keyword: let keyword, wholeWord: let wholeWord):
                keywordsParams.append("keywords_attributes[\(index)][keyword]" => keyword)
                keywordsParams.append("keywords_attributes[\(index)][whole_word]" => wholeWord)
            default:
                fatalError("can only add keywords when creating filter")
            }
        }
        return Request(method: .post, path: "/api/v2/filters", body: ParametersBody([
            "title" => title,
            "expires_in" => expiresIn,
            "filter_action" => action.rawValue,
        ] + "context" => context.contextStrings + keywordsParams))
    }
    
    private enum CodingKeys: String, CodingKey {
        case id
        case title
        case context
        case expiresAt = "expires_at"
        case action = "filter_action"
        case keywords
    }
}

extension FilterV2 {
    public enum Action: String, Decodable, Hashable, CaseIterable, Sendable {
        case warn
        case hide
    }
}

extension FilterV2 {
    public struct Keyword: Decodable, Sendable {
        public let id: String
        public let keyword: String
        public let wholeWord: Bool
        
        public init(id: String, keyword: String, wholeWord: Bool) {
            self.id = id
            self.keyword = keyword
            self.wholeWord = wholeWord
        }
        
        private enum CodingKeys: String, CodingKey {
            case id
            case keyword
            case wholeWord = "whole_word"
        }
    }
}

extension FilterV2 {
    public enum KeywordUpdate {
        case update(id: String, keyword: String, wholeWord: Bool)
        case add(keyword: String, wholeWord: Bool)
        case destroy(id: String)
    }
}
