//
//  AnalyticsDefinition.swift
//
//
//  Created by Loris Perret on 05/12/2023.
//

import Foundation
import ToolCore

class AnalyticsDefinition {

    // MARK: - Properties

    let id: String
    var name: String
    var path: String = ""
    var category: String = ""
    var action: String = ""
    var comments: String = ""
    var tags: [String] = []
    var parameters: [AnalyticsParameter] = []
    var type: TagType

    // MARK: - Init

    init(id: String, name: String, type: TagType) {
        self.id = id
        self.name = name
        self.type = type
    }

    // MARK: - Methods

    func hasOneOrMoreMatchingTags(inputTags: [String]) -> Bool {
        if Set(inputTags).isDisjoint(with: tags) {
            return false
        }
        return true
    }

    // MARK: - Private Methods

    private func getFuncName() -> String {
        var pascalCaseTitle: String = ""
        id.components(separatedBy: "_").forEach { word in
            pascalCaseTitle.append(contentsOf: word.uppercasedFirst())
        }

        return "log\(type == .screen ? "Screen" : "Event")\(pascalCaseTitle)"
    }

    private func getParameters() -> String {
        var params = parameters
        var result: String

        if type == .screen {
            params = params.filter { param in
                !param.replaceIn.isEmpty
            }
        }

        let paramsString = params.map { parameter in
            "\(parameter.name): \(parameter.type)"
        }

        if paramsString.count > 2 {
            result = """
            (
                    \(paramsString.joined(separator: ",\n\t\t"))
                )
            """
        } else {
            result = """
            (\(paramsString.joined(separator: ", ")))
            """
        }

        return result
    }

    private func replaceIn() {
        for parameter in parameters {
            for rep in parameter.replaceIn {
                switch rep {
                case "name": name = name.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
                case "path": path = path.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
                case "category": category = category.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
                case "action": action = action.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
                default: break
                }
            }
        }
    }

    private func getlogFunction() -> String {
        var params: [String] = []
        var result: String

        let supplementaryParams = parameters.filter { param in
            param.replaceIn.isEmpty
        }

        supplementaryParams.forEach { param in
            params.append("\"\(param.name)\": \(param.name)")
        }

        if params.count > 1 {
            result = """
            [
                            \(params.joined(separator: ",\n\t\t\t\t"))
                        ]
            """
        } else if params.count == 1 {
            result = """
            [\(params.joined(separator: ", "))]
            """
        } else {
            result = "[:]"
        }

        if type == .screen {
            return """
            logScreen(
                        name: "\(name)",
                        path: "\(path)"
                    )
            """
        } else {
            return """
            logEvent(
                        name: "\(name)",
                        action: "\(action)",
                        category: "\(category)",
                        params: \(result)
                    )
            """
        }
    }

    // MARK: - Raw strings

    func getProperty() -> String {
        replaceIn()
        return """
            func \(getFuncName())\(getParameters()) {
                \(getlogFunction())
            }
        """
    }

    func getStaticProperty() -> String {
        replaceIn()
        return """
            static func \(getFuncName())\(getParameters()) {
                \(getlogFunction())
            }
        """
    }
}
