//
//  Images.swift
//
//
//  Created by Thibaut Schmitt on 24/01/2022.
//

import ArgumentParser
import Foundation
import ToolCore

struct Images: ParsableCommand {

    // MARK: - CommandConfiguration

    static let configuration = CommandConfiguration(
        abstract: "A utility for generate images and an extension to access them easily.",
        version: ResgenSwiftVersion
    )

    // MARK: - Static

    static let toolName = "Images"

    // MARK: - Command Options

    @OptionGroup var options: ImagesOptions

    // MARK: - Run

    mutating func run() {
        print("[\(Self.toolName)] Starting images generation")
        print("[\(Self.toolName)] Will use inputFile \(options.inputFile) to generate images in xcassets \(options.xcassetsPath)")

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

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

        // Parse input file
        let imagesToGenerate = ImageFileParser.parse(options.inputFile, platform: PlatormTag.ios)

        // Generate xcassets files
        let inputFolder = URL(fileURLWithPath: options.inputFile)
            .deletingLastPathComponent()
            .relativePath

        let xcassetsGenerator = XcassetsGenerator(forceGeneration: options.forceExecutionAndGeneration)
        xcassetsGenerator.generateXcassets(
            inputPath: inputFolder,
            imagesToGenerate: imagesToGenerate,
            xcassetsPath: options.xcassetsPath
        )

        // Generate extension
        if let extensionName = options.extensionName,
           let extensionFilePath = options.extensionFilePath {
            ImageExtensionGenerator.generateExtensionFile(
                images: imagesToGenerate,
                isStatic: options.staticMembers,
                inputFilename: options.inputFilenameWithoutExt,
                extensionName: extensionName,
                extensionFilePath: extensionFilePath,
                isSwiftUI: true,
                visibility: options.extensionVisibility,
                assetBundle: options.assetBundle
            )
        }

        if let extensionNameUIKit = options.extensionNameUIKit,
           let extensionFilePathUIKit = options.extensionFilePathUIKit {
            ImageExtensionGenerator.generateExtensionFile(
                images: imagesToGenerate,
                isStatic: options.staticMembers,
                inputFilename: options.inputFilenameWithoutExt,
                extensionName: extensionNameUIKit,
                extensionFilePath: extensionFilePathUIKit,
                isSwiftUI: false,
                visibility: options.extensionVisibility,
                assetBundle: options.assetBundle
            )
        }

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

    // MARK: - Requirements

    private func checkRequirements() -> Bool {
        guard options.forceExecutionAndGeneration == false else {
            return true
        }

        let fileManager = FileManager()

        // Input file
        guard fileManager.fileExists(atPath: options.inputFile) else {
            let error = ImagesError.fileNotExists(options.inputFile)
            print(error.description)
            Self.exit(withError: error)
        }

        // RSVG-Converter
        _ = Self.getSvgConverterPath()

        // Extension for UIKit and SwiftUI should have different name
        if let extensionName = options.extensionName,
           let extensionNameUIKit = options.extensionNameUIKit {
            guard extensionName != extensionNameUIKit else {
                let error = ImagesError.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 = ImagesError.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.forceExecution,
            inputFilePath: options.inputFile,
            extensionFilePath: fileToCompareToInput
        ) else {
            print("[\(Self.toolName)] Images are already up to date :) ")
            return false
        }

        return true
    }

    // MARK: - Helpers

    @discardableResult
    static func getSvgConverterPath() -> String {
        let taskSvgConverter = Shell.shell(["which", "rsvg-convert"])
        if taskSvgConverter.terminationStatus == 0 {
            return taskSvgConverter.output!.removeCharacters(from: CharacterSet.whitespacesAndNewlines) // swiftlint:disable:this force_unwrapping
        }

        let error = ImagesError.rsvgConvertNotFound
        print(error.description)
        Self.exit(withError: error)
    }

    @discardableResult
    static func getMagickConvertPath() -> String {
        // WARNING: The convert command is deprecated in IMv7, use "magick" instead of "convert"
        let taskMagick = Shell.shell(["which", "magick"])
        if taskMagick.terminationStatus == 0 {
            return taskMagick.output!.removeCharacters(from: CharacterSet.whitespacesAndNewlines) // swiftlint:disable:this force_unwrapping
        }

        let taskConvert = Shell.shell(["which", "convert"])
        if taskConvert.terminationStatus == 0 {
            return taskMagick.output!.removeCharacters(from: CharacterSet.whitespacesAndNewlines) // swiftlint:disable:this force_unwrapping
        }

        let error = ImagesError.magickConvertNotFound
        print(error.description)
        Self.exit(withError: error)
    }
}
