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

import ArgumentParser
import Foundation
import ToolCore

struct Images: ParsableCommand {

    // MARK: - CommandConfiguration

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

    // MARK: - Static

    static let toolName = "Images"
    static let defaultExtensionName = "Image"
    static let defaultExtensionNameUIKit = "UIImage"

    // 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
        ImageExtensionGenerator.generateExtensionFile(
            images: imagesToGenerate,
            staticVar: options.staticMembers,
            inputFilename: options.inputFilenameWithoutExt,
            extensionName: options.extensionName,
            extensionFilePath: options.extensionFilePath,
            isSwiftUI: true
        )

        ImageExtensionGenerator.generateExtensionFile(
            images: imagesToGenerate,
            staticVar: options.staticMembers,
            inputFilename: options.inputFilenameWithoutExt,
            extensionName: options.extensionNameUIKit,
            extensionFilePath: options.extensionFilePathUIKit,
            isSwiftUI: false
        )

        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
        guard options.extensionName != options.extensionNameUIKit else {
            let error = ImagesError.extensionNamesCollision(options.extensionName)
            print(error.description)
            Self.exit(withError: error)
        }

        // Check if needed to regenerate
        guard GeneratorChecker.shouldGenerate(
            force: options.forceExecution,
            inputFilePath: options.inputFile,
            extensionFilePath: options.extensionFilePath
        ) 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)
    }
}
