//
//  Stringium.swift
//
//
//  Created by Thibaut Schmitt on 10/01/2022.
//

import ArgumentParser
import Foundation
import ToolCore

struct Stringium: ParsableCommand {

    // MARK: - Command Configuration

    static let configuration = CommandConfiguration(
        abstract: "Generate strings with custom scripts.",
        version: ResgenSwiftVersion
    )

    // MARK: - Static

    static let toolName = "Stringium"
    static let noTranslationTag: String = "notranslation"

    // MARK: - Command options

    @OptionGroup var options: StringiumOptions

    // MARK: - Run

    mutating func run() {
        print("[\(Self.toolName)] Starting strings generation")
        print("[\(Self.toolName)] Will use inputFile \(options.inputFile) to generate strings for \(options.langs) (default lang: \(options.defaultLang))")

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

        print("[\(Self.toolName)] Will generate \(options.xcStrings ? "xcStrings catalog" : "legacy strings file")")

        // Parse input file
        let sections = TwineFileParser.parse(options.inputFile)

        // Generate strings files
        if !options.xcStrings {
            StringsFileGenerator.writeStringsFiles(
                sections: sections,
                langs: options.langs,
                defaultLang: options.defaultLang,
                tags: options.tags,
                lprojPathFormat: options.lprojPathFormat
            )
        } else {
            StringsFileGenerator.writeXcStringsFiles(
                sections: sections,
                langs: options.langs,
                defaultLang: options.defaultLang,
                tags: options.tags,
                xcStringsFilePath: options.xcStringsFilePath
            )
        }

        // Generate extension
        if let extensionName = options.extensionName,
            let extensionFilePath = options.extensionFilePath {
            print("Will generate extensions")
            StringsFileGenerator.writeExtensionFiles(
                sections: sections,
                defaultLang: options.defaultLang,
                tags: options.tags,
                isStatic: options.staticMembers,
                inputFilename: options.inputFilenameWithoutExt,
                extensionName: extensionName,
                extensionFilePath: extensionFilePath,
                extensionSuffix: options.extensionSuffix ?? "",
                visibility: options.extensionVisibility,
                assetBundle: options.assetBundle
            )
        }

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

    // MARK: - Requirements

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

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

        // Langs
        guard options.langs.isEmpty == false else {
            let error = StringiumError.langsListEmpty
            print(error.description)
            Self.exit(withError: error)
        }

        guard options.langs.contains(options.defaultLang) else {
            let error = StringiumError.defaultLangsNotInLangs
            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 options.xcStrings {
                return options.xcStringsFilePath
            }
            return String(format: options.lprojPathFormat, options.defaultLang)
        }()
        guard GeneratorChecker.shouldGenerate(
            force: options.forceGeneration,
            inputFilePath: options.inputFile,
            extensionFilePath: fileToCompareToInput
        ) else {
            print("[\(Self.toolName)] Strings are already up to date :) ")
            return false
        }

        return true
    }
}
