//
//  StringsFileGeneratorTests.swift
//
//
//  Created by Thibaut Schmitt on 06/09/2022.
//

import Foundation
import XCTest
import ToolCore

@testable import ResgenSwift

final class StringsFileGeneratorTests: XCTestCase {

    // MARK: - Strings File Content

    func testGenerateStringsFileContent() {
        // Given
        let sectionOne = Section.Mock.getSectionOne()
        let sectionTwo = Section.Mock.getSectionTwo()

        // When
        let stringsFileContentFr = StringsFileGenerator.generateStringsFileContent(
            lang: "fr",
            defaultLang: "fr",
            tags: ["ios", "iosonly", "notranslation"],
            sections: [sectionOne, sectionTwo]
        )
        let stringsFileContentEn = StringsFileGenerator.generateStringsFileContent(
            lang: "en",
            defaultLang: "fr",
            tags: ["ios", "iosonly", "notranslation"],
            sections: [sectionOne, sectionTwo]
        )

        // Expect
        XCTAssertEqual(
            stringsFileContentFr.adaptForXCTest(),
            Self.appleStringsFileExpectationFr.adaptForXCTest()
        )
        XCTAssertEqual(
            stringsFileContentEn.adaptForXCTest(),
            Self.appleStringsFileExpectationEn.adaptForXCTest()
        )
    }

    func testGenerateStringsFileContentWithComment() {
        // Given
        let sectionOne = Section.Mock.getSectionOne(
            defOneComment: "This is a comment",
            defTwoComment: "This is a comment"
        )
        let sectionTwo = Section.Mock.getSectionTwo(
            defOneComment: "This is a comment",
            defTwoComment: "This is a comment"
        )

        // When
        let stringsFileContentFr = StringsFileGenerator.generateStringsFileContent(
            lang: "fr",
            defaultLang: "fr",
            tags: ["ios", "iosonly", "notranslation"],
            sections: [sectionOne, sectionTwo]
        )
        let stringsFileContentEn = StringsFileGenerator.generateStringsFileContent(
            lang: "en",
            defaultLang: "fr",
            tags: ["ios", "iosonly", "notranslation"],
            sections: [sectionOne, sectionTwo]
        )

        // Expect
        XCTAssertEqual(
            stringsFileContentFr.adaptForXCTest(),
            Self.appleStringsFileExpectationFr.adaptForXCTest()
        )
        XCTAssertEqual(
            stringsFileContentEn.adaptForXCTest(),
            Self.appleStringsFileExpectationEn.adaptForXCTest()
        )
    }

    // MARK: - XcString File Content

    func testGenerateXcStringsRootObject() {
        // Given
        let sectionOne = Section.Mock.getSectionOne()
        let sectionTwo = Section.Mock.getSectionTwo(
            defTwoEn: "Section Two - Definition Two"
        )

        // When
        let rootObject = StringsFileGenerator.generateRootObject(
            langs: ["fr", "en"],
            defaultLang: "en",
            tags: ["ios", "iosonly", "notranslation"],
            sections: [sectionOne, sectionTwo]
        )

        // Expect
        let expect =
        Root(
            sourceLanguage: "en",
            strings: XCStringDefinitionContainer(
                strings: [
                    XCStringDefinition(
                        title: "s1_def_one",
                        content: XCStringDefinitionContent(
                            extractionState: "manual",
                            localizations: XCStringLocalizationContainer(
                                localizations: [
                                    XCStringLocalization(
                                        lang: "en",
                                        content: XCStringLocalizationLangContent(
                                            stringUnit: DefaultStringUnit(
                                                state: "translated",
                                                value: "Section One - Definition One"
                                            )
                                        )
                                    ),
                                    XCStringLocalization(
                                        lang: "fr",
                                        content: XCStringLocalizationLangContent(
                                            stringUnit: DefaultStringUnit(
                                                state: "translated",
                                                value: "Section Un - Definition Un"
                                            )
                                        )
                                    )
                                ]
                            )
                        )
                    ),
                    XCStringDefinition(
                        title: "s1_def_two",
                        content: XCStringDefinitionContent(
                            extractionState: "manual",
                            localizations: XCStringLocalizationContainer(
                                localizations: [
                                    XCStringLocalization(
                                        lang: "en",
                                        content: XCStringLocalizationLangContent(
                                            stringUnit: DefaultStringUnit(
                                                state: "translated",
                                                value: "Section One - Definition Two"
                                            )
                                        )
                                    ),
                                    XCStringLocalization(
                                        lang: "fr",
                                        content: XCStringLocalizationLangContent(
                                            stringUnit: DefaultStringUnit(
                                                state: "translated",
                                                value: "Section Un - Definition Deux"
                                            )
                                        )
                                    )
                                ]
                            )
                        )
                    ),
                    XCStringDefinition(
                        title: "s2_def_one",
                        content: XCStringDefinitionContent(
                            extractionState: "manual",
                            localizations: XCStringLocalizationContainer(
                                localizations: [
                                    XCStringLocalization(
                                        lang: "en",
                                        content: XCStringLocalizationLangContent(
                                            stringUnit: DefaultStringUnit(
                                                state: "translated",
                                                value: "Section Two - Definition One"
                                            )
                                        )
                                    ),
                                    XCStringLocalization(
                                        lang: "fr",
                                        content: XCStringLocalizationLangContent(
                                            stringUnit: DefaultStringUnit(
                                                state: "translated",
                                                value: "Section Deux - Definition Un"
                                            )
                                        )
                                    )
                                ]
                            )
                        )
                    ),
                    XCStringDefinition(
                        title: "s2_def_two",
                        content: XCStringDefinitionContent(
                            extractionState: "manual",
                            localizations: XCStringLocalizationContainer(
                                localizations: [
                                    XCStringLocalization(
                                        lang: "en",
                                        content: XCStringLocalizationLangContent(
                                            stringUnit: DefaultStringUnit(
                                                state: "translated",
                                                value: "Section Two - Definition Two"
                                            )
                                        )
                                    ),
                                    XCStringLocalization(
                                        lang: "fr",
                                        content: XCStringLocalizationLangContent(
                                            stringUnit: DefaultStringUnit(
                                                state: "translated",
                                                value: "Section Two - Definition Two"
                                            )
                                        )
                                    )
                                ]
                            )
                        )
                    )
                ]
            ),
            version: "1.0"
        )

        XCTAssertEqual(rootObject, expect)
    }

    func testGenerateXcStringsRootObjectWithEmptyTranslations() {
        // Given
        let sectionOne = Section.Mock.getSectionOne(
            defOneFr: "",
            defTwoFr: ""
        )
        let sectionTwo = Section.Mock.getSectionTwo(
            defOneFr: "",
            defTwoFr: "",
            defTwoEn: "Section Two - Definition Two"
        )
        // By default Section2.s2_def_two has a fr value => remove it
        sectionTwo.definitions
            .first { def in
                def.name == "s2_def_two"
            }?
            .translations.removeValue(forKey: "fr")

        // When
        let rootObject = StringsFileGenerator.generateRootObject(
            langs: ["fr", "en"],
            defaultLang: "en",
            tags: ["ios", "iosonly", "notranslation"],
            sections: [sectionOne, sectionTwo]
        )

        // Expect
        let expect =
        Root(
            sourceLanguage: "en",
            strings: XCStringDefinitionContainer(
                strings: [
                    XCStringDefinition.Mock.getDefinitionSectionOne(
                        defOneFr: "",
                        defTwoFr: "",
                    ),
                    XCStringDefinition.Mock.getDefinitionSectionTwo(
                        defOneFr: "",
                        defTwoFr: "Section Two - Definition Two",
                        defTwoEn: "Section Two - Definition Two",
                    )
                ]
                    .flatMap { $0 }
            ),
            version: "1.0"
        )

        XCTAssertEqual(rootObject, expect)
    }

    func testGenerateXcStringsRootObjectWithNoTranslations() {
        // Given
        let sectionOne = Section.Mock.getSectionOne(
            defOneFr: "",
            defOneEn: "",
            defTwoFr: "",
            defTwoEn : ""
        )
        let sectionTwo = Section.Mock.getSectionTwo(
            defOneFr: "",
            defOneEn: "",
            defTwoFr: "",
            defTwoEn : ""
        )

        // When
        let rootObject = StringsFileGenerator.generateRootObject(
            langs: ["fr", "en"],
            defaultLang: "en",
            tags: ["ios", "iosonly", "notranslation"],
            sections: [sectionOne, sectionTwo]
        )

        // Expect
        let expect =
        Root(
            sourceLanguage: "en",
            strings: XCStringDefinitionContainer(
                strings: [
                        XCStringDefinition.Mock.getDefinitionSectionOne(
                            defOneFr: "",
                            defOneEn: "",
                            defTwoFr: "",
                            defTwoEn : ""
                        ),
                        XCStringDefinition.Mock.getDefinitionSectionTwo(
                            defOneFr: "",
                            defOneEn: "",
                            defTwoFr: "",
                            defTwoEn : ""
                        )
                    ]
                    .flatMap { $0 }
            ),
            version: "1.0"
        )

        XCTAssertEqual(rootObject, expect)
    }

    func testGenerateXcStringsRootObjectWithComments() {
        // Given
        let sectionOne = Section.Mock.getSectionOne(
            defOneComment: "Comment 1",
            defTwoComment: "Comment 2"
        )
        let sectionTwo = Section.Mock.getSectionTwo()

        // When
        let rootObject = StringsFileGenerator.generateRootObject(
            langs: ["fr", "en"],
            defaultLang: "fr",
            tags: ["ios", "iosonly", "notranslation"],
            sections: [sectionOne, sectionTwo]
        )

        // Expect
        let expect =
        Root(
            sourceLanguage: "fr",
            strings: XCStringDefinitionContainer(
                strings: [
                    XCStringDefinition.Mock.getDefinitionSectionOne(
                        defOneComment: "Comment 1",
                        defTwoComment: "Comment 2"
                    ),
                    XCStringDefinition.Mock.getDefinitionSectionTwo(
                        // SourceLanguage is frn en definition should the same as fr
                        defTwoEn: "Section Deux - Definition Deux"
                    )
                ]
                    .flatMap { $0 }
            ),
            version: "1.0"
        )

        XCTAssertEqual(rootObject, expect)
    }

    // MARK: - Extension Content

    func testGeneratedExtensionContent() {
        // Given
        let sectionOne = Section.Mock.getSectionOne()
        let sectionTwo = Section.Mock.getSectionTwo()

        // When
        let extensionContent = StringsFileGenerator.getExtensionContent(sections: [sectionOne, sectionTwo],
                                                                        defaultLang: "fr",
                                                                        tags: ["ios", "iosonly", "notranslation"],
                                                                        staticVar: false,
                                                                        inputFilename: "myInputFilename",
                                                                        extensionName: "GenStrings",
                                                                        extensionSuffix: "strings")

        // Expect
        let expect = Self.getExtensionContentExpectation(
            staticVar: false
        )

        if extensionContent != expect {
            print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect))
        }
        XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest())
    }

    func testGeneratedExtensionContentWithComment() {
        // Given
        let sectionOne = Section.Mock.getSectionOne(
            defOneComment: "This is a comment",
            defTwoComment: "This is a comment"
        )
        let sectionTwo = Section.Mock.getSectionTwo(
            defOneComment: "This is a comment",
            defTwoComment: "This is a comment"
        )

        // When
        let extensionContent = StringsFileGenerator.getExtensionContent(sections: [sectionOne, sectionTwo],
                                                                        defaultLang: "fr",
                                                                        tags: ["ios", "iosonly", "notranslation"],
                                                                        staticVar: false,
                                                                        inputFilename: "myInputFilename",
                                                                        extensionName: "GenStrings",
                                                                        extensionSuffix: "strings")

        // Expect
        let expect = Self.getExtensionContentExpectation(
            staticVar: false,
            s1DefOneComment: "This is a comment",
            s1DefTwoComment: "This is a comment",
            s2DefOneComment: "This is a comment",
            s2DefTwoComment: "This is a comment",
        )

        if extensionContent != expect {
            print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect))
        }
        XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest())
    }

    // MARK: - Extension Content Static
    func testGeneratedExtensionContentWithStaticVar() {
        // Given
        let sectionOne = Section.Mock.getSectionOne()
        let sectionTwo = Section.Mock.getSectionTwo()

        // When
        let extensionContent = StringsFileGenerator.getExtensionContent(sections: [sectionOne, sectionTwo],
                                                                        defaultLang: "fr",
                                                                        tags: ["ios", "iosonly", "notranslation"],
                                                                        staticVar: true,
                                                                        inputFilename: "myInputFilename",
                                                                        extensionName: "GenStrings",
                                                                        extensionSuffix: "strings")

        // Expect
        let expect = Self.getExtensionContentExpectation(
            staticVar: true
        )

        if extensionContent != expect {
            print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect))
        }
        XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest())
    }

    func testGeneratedExtensionContentWithStaticVarWithComment() {
        // Given
        let sectionOne = Section.Mock.getSectionOne(
            defOneComment: "This is a comment",
            defTwoComment: "This is a comment"
        )
        let sectionTwo = Section.Mock.getSectionTwo(
            defOneComment: "This is a comment",
            defTwoComment: "This is a comment"
        )

        // When
        let extensionContent = StringsFileGenerator.getExtensionContent(sections: [sectionOne, sectionTwo],
                                                                        defaultLang: "fr",
                                                                        tags: ["ios", "iosonly", "notranslation"],
                                                                        staticVar: true,
                                                                        inputFilename: "myInputFilename",
                                                                        extensionName: "GenStrings",
                                                                        extensionSuffix: "strings")

        // Expect
        let expect = Self.getExtensionContentExpectation(
            staticVar: true,
            s1DefOneComment: "This is a comment",
            s1DefTwoComment: "This is a comment",
            s2DefOneComment: "This is a comment",
            s2DefTwoComment: "This is a comment",
        )

        if extensionContent != expect {
            print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect))
        }
        XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest())
    }
}

