//
//  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 result: String

        let paramsString = parameters.compactMap { parameter -> String? in
            guard parameter.value.isEmpty else { return nil }

            let defaultValue: String
            switch parameter.type {
            case .bool:
                defaultValue = "\(parameter.defaultValue.lowercased())"

            case .int, .double:
                defaultValue = "\(parameter.defaultValue)"

            case .string:
                defaultValue = "\"\(parameter.defaultValue)\""
            }

            let defaultValueString = parameter.defaultValue.isEmpty ? "" : " = \(defaultValue)"
            return "\(parameter.name): \(parameter.type.rawValue)\(defaultValueString)"
        }

        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:
                    if let param = parameters.first(where: { $0.name == rep }), param.value.isEmpty == false {
                        param.value = param.value.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
                    }
                }
            }
        }
    }

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

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

        supplementaryParams.forEach { param in
            if param.value.isEmpty {
                params.append("\"\(param.name)\": \(param.name)")
            } else {
                switch param.type {
                case .bool:
                    params.append("\"\(param.name)\": \(param.value.lowercased())")

                case .int, .double:
                    params.append("\"\(param.name)\": \(param.value)")

                case .string:
                    params.append("\"\(param.name)\": \"\(param.value)\"")
                }
            }
        }

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

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

    // MARK: - Raw strings

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

    func getStaticProperty(visibility: ExtensionVisibility) -> String {
        replaceIn()
        return """
            \(visibility) static func \(getFuncName())\(getParameters()) {
                AnalyticsManager.shared.\(getlogFunction())
            }
        """
    }
}
