//
//  AnalyticsGenerator.swift
//
//
//  Created by Loris Perret on 08/12/2023.
//

import Foundation
import ToolCore
import CoreVideo

class AnalyticsGenerator {
    static var targets: [TrackerType] = []

    static func writeExtensionFiles(sections: [AnalyticsCategory], target: String, tags: [String], staticVar: Bool, extensionName: String, extensionFilePath: String) {
        // Get target type from enum
        let targetsString: [String] = target.components(separatedBy: " ")
                
        TrackerType.allCases.forEach { enumTarget in
            if targetsString.contains(enumTarget.value) {
                targets.append(enumTarget)
            }
        }
        
        // Get extension content
        let extensionFileContent = Self.getExtensionContent(sections: sections,
                                                            tags: tags,
                                                            staticVar: staticVar,
                                                            extensionName: extensionName)
        
        // Write content
        let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
        do {
            try extensionFileContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
        } catch let error {
            let error = AnalyticsError.writeFile(extensionFilePath, error.localizedDescription)
            print(error.description)
            Analytics.exit(withError: error)
        }
    }
    
    // MARK: - Extension content
    
    static func getExtensionContent(sections: [AnalyticsCategory], tags: [String], staticVar: Bool, extensionName: String) -> String {
        [
            Self.getHeader(extensionClassname: extensionName, staticVar: staticVar),
            Self.getProperties(sections: sections, tags: tags, staticVar: staticVar),
            Self.getFooter()
        ]
            .joined(separator: "\n")
    }
    
    // MARK: - Extension part
    
    private static func getHeader(extensionClassname: String, staticVar: Bool) -> String {
        """
        // Generated by ResgenSwift.\(Analytics.toolName) \(ResgenSwiftVersion)
        
        \(Self.getImport())
        
        \(Self.getAnalyticsProtocol())
        // MARK: - Manager
        
        class AnalyticsManager {
            static var shared = AnalyticsManager()
            
            // MARK: - Properties
        
            var managers: [AnalyticsManagerProtocol] = []
        
            \(Self.getEnabledContent())
        
            \(Self.getAnalyticsProperties())
                
            \(Self.getPrivateLogFunction())
        """
    }
    
    private static func getEnabledContent() -> String {
        """
        private var isEnabled: Bool = true
        
            // MARK: - Methods
        
            func setAnalyticsEnabled(_ enable: Bool) {
                isEnabled = enable
            }
        """
    }
    
    private static func getImport() -> String {
        var result: [String] = []
        
        if targets.contains(TrackerType.matomo) {
            result.append("import MatomoTracker")
        }
        if targets.contains(TrackerType.firebase) {
            result.append("import FirebaseAnalytics")
        }
        
        return result.joined(separator: "\n")
    }
    
    private static func getPrivateLogFunction() -> String {
        """
        private func logScreen(name: String, path: String) {
                guard isEnabled else { return }
        
                managers.forEach { manager in
                    manager.logScreen(name: name, path: path)
                }
            }
            
            private func logEvent(
                name: String,
                action: String,
                category: String,
                params: [String: Any]?
            ) {
                guard isEnabled else { return }
        
                managers.forEach { manager in
                    manager.logEvent(
                        name: name,
                        action: action,
                        category: category,
                        params: params
                    )
                }
            }
        """
    }
    
    private static func getAnalyticsProperties() -> String {
        var header = ""
        var content: [String] = []
        let footer = "    }"
        
        if targets.contains(TrackerType.matomo) {
            header = "func configure(siteId: String, url: String) {"
        } else if targets.contains(TrackerType.firebase) {
            header = "func configure() {"
        }
        
        if targets.contains(TrackerType.matomo) {
            content.append("""
                    managers.append(
                        MatomoAnalyticsManager(
                            siteId: siteId,
                            url: url
                        )
                    )
            """)
        }
        if targets.contains(TrackerType.firebase) {
            content.append("        managers.append(FirebaseAnalyticsManager())")
        }
        
        return [
            header,
            content.joined(separator: "\n"),
            footer
        ]
            .joined(separator: "\n")
    }
    
    private static func getAnalyticsProtocol() -> String {
        let proto = """
        // MARK: - Protocol
        
        protocol AnalyticsManagerProtocol {
            func logScreen(name: String, path: String)
            func logEvent(
                name: String,
                action: String,
                category: String,
                params: [String: Any]?
            )
        }
        
        """
        
        var result: [String] = [proto]
        
        if targets.contains(TrackerType.matomo) {
            result.append(MatomoGenerator.service)
        }
        
        if targets.contains(TrackerType.firebase) {
            result.append(FirebaseGenerator.service)
        }
        
        return result.joined(separator: "\n")
    }
    
    private static func getProperties(sections: [AnalyticsCategory], tags: [String], staticVar: Bool) -> String {
        sections
            .compactMap { section in
                // Check that at least one string will be generated
                guard section.hasOneOrMoreMatchingTags(tags: tags) else {
                    return nil// Go to next section
                }
                
                var res = "\n    // MARK: - \(section.id)"
                section.definitions.forEach { definition in
                    guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else {
                        return // Go to next definition
                    }
                    
                    if staticVar {
                        res += "\n\n\(definition.getStaticProperty())"
                    } else {
                        res += "\n\n\(definition.getProperty())"
                    }
                }
                return res
            }
            .joined(separator: "\n")
    }
    
    private static func getFooter() -> String {
        """
        }
        
        """
    }
}
