//
//  main.swift
//
//
//  Created by Thibaut Schmitt on 20/12/2021.
//

@preconcurrency import ArgumentParser
import Foundation
import ToolCore

struct Colors: ParsableCommand {

    // MARK: - CommandConfiguration

    static let configuration = CommandConfiguration(
        abstract: "A utility for generate colors assets and their getters.",
        version: ResgenSwiftVersion
    )

    // MARK: - Static

    static let toolName = "Color"
    static let assetsColorsFolderName = "Colors"

    // MARK: - Command options

    @OptionGroup var options: ColorsToolOptions

    // MARK: - Run

    func run() throws {
        print("[\(Self.toolName)] Starting colors generation")

        // Check requirements
        guard checkRequirements() else { return }

        print("[\(Self.toolName)] Will generate colors")

        // Delete current colors
        deleteCurrentColors()

        // Get colors to generate
        let parsedColors = ColorFileParser.parse(
            options.inputFile,
            colorStyle: options.style
        )
        // -> Time: 0.0020350217819213867 seconds

        // Generate all colors in xcassets
        ColorXcassetHelper.generateXcassetColors(
            colors: parsedColors,
            to: options.xcassetsPath
        )
        // -> Time: 3.4505380392074585 seconds

        // Generate extension
        if let extensionName = options.extensionName,
           let extensionFilePath = options.extensionFilePath {
            ColorExtensionGenerator.writeExtensionFile(
                colors: parsedColors,
                isStatic: options.staticMembers,
                extensionName: extensionName,
                extensionFilePath: extensionFilePath,
                isSwiftUI: true,
                visibility: options.extensionVisibility,
                assetBundle: options.assetBundle
            )
        }

        // Generate extension
        if let extensionNameUIKit = options.extensionNameUIKit,
           let extensionFilePathUIKit = options.extensionFilePathUIKit {
            ColorExtensionGenerator.writeExtensionFile(
                colors: parsedColors,
                isStatic: options.staticMembers,
                extensionName: extensionNameUIKit,
                extensionFilePath: extensionFilePathUIKit,
                isSwiftUI: false,
                visibility: options.extensionVisibility,
                assetBundle: options.assetBundle
            )
        }

        print("[\(Self.toolName)] Colors generated")
    }

    // MARK: - Requirements

    private func checkRequirements() -> Bool {
        let fileManager = FileManager()

        // Check if input file exists
        guard fileManager.fileExists(atPath: options.inputFile) else {
            let error = ColorsToolError.fileNotExists(options.inputFile)
            print(error.description)
            Self.exit(withError: error)
        }

        // Check if xcassets file exists
        guard fileManager.fileExists(atPath: options.xcassetsPath) else {
            let error = ColorsToolError.fileNotExists(options.xcassetsPath)
            print(error.description)
            Self.exit(withError: error)
        }

        // Extension for UIKit and SwiftUI should have different name (if both are defined)
        if let extensionName = options.extensionName,
           let extensionNameUIKit = options.extensionNameUIKit {
            guard extensionName != extensionNameUIKit else {
                let error = ColorsToolError.extensionNamesCollision(extensionName)
                print(error.description)
                Self.exit(withError: error)
            }
        }

        // If an extension need to be generated, ensure extensionOutputPath is defined
        if options.extensionName != nil ||
            options.extensionNameUIKit != nil {
            guard let extensionOutputPath = options.extensionOutputPath,
                  extensionOutputPath.isEmpty == false else {
                let error = ColorsToolError.missingExtensionPath
                print(error.description)
                Self.exit(withError: error)
            }
        }

        // Check if needed to regenerate
        let fileToCompareToInput: String = {
            // If there is no extension file to compare
            // Then check the xcassets file instead
            if let extensionFilePath = options.extensionFilePath {
                return extensionFilePath
            }
            return options.xcassetsPath
        }()
        guard GeneratorChecker.shouldGenerate(
            force: options.forceGeneration,
            inputFilePath: options.inputFile,
            extensionFilePath: fileToCompareToInput
        ) else {
            print("[\(Self.toolName)] Colors are already up to date :) ")
            return false
        }

        return true
    }

    // MARK: - Helpers

    private func deleteCurrentColors() {
        let fileManager = FileManager()
        let assetsColorPath = "\(options.xcassetsPath)/Colors"

        if fileManager.fileExists(atPath: assetsColorPath) {
            do {
                try fileManager.removeItem(atPath: assetsColorPath)
            } catch {
                let error = ColorsToolError.deleteExistingColors("\(options.xcassetsPath)/Colors")
                print(error.description)
                Self.exit(withError: error)
            }
        }
    }
}
