package cli

import (
    "bufio"
    "fmt"
    "strconv"
    "strings"
    "os"
    "gitea.armuli.eu/museum-digital/museum-digital-webdav-uploader/src/configloader"
)

// Interal wrapper around opening a new bufio.Reader and getting an input
// from it. As errors here likely really are something fundamentally wrong
// about the system, panic if there is one.
func getConsoleInput() string {

    reader := bufio.NewReader(os.Stdin)
    output, err := reader.ReadString('\n')

    if err != nil {
        fmt.Println("Failed to get console input!")
        panic(err)
    }

    return strings.Trim(output, "\n\r")

}

// Prompts the user to enter a valid instance url until they do.
func requestInstanceLink() string {

    fmt.Println("\nPlease enter URL of the instance of museum-digital you work in.")
    fmt.Println("This should be a regional instance (e.g. hessen.museum-digital.de), not an aggregated one like nat.museum-digital.de.")

    input := getConsoleInput()

    output, validationErr := configloader.ValidateInstanceLink(input)
    if validationErr != nil {
        fmt.Println("This is not a valid instance of museum-digital / musdb. Please try again.")
        fmt.Print("----\nThe specific error is:\n")
        fmt.Println(validationErr)
        fmt.Print("----\n\n")
        return requestInstanceLink()
    }

    return output

}

// Prompts the user to enter a valid institution ID within the
// specified instance until they do.
func requestInstitutionId(instanceLink string) int {

    fmt.Println("\nPlease enter ID of your institution.")
    fmt.Println("You can find the ID of the institution ID in musdb. On the institution/museum editing page, you will find it as a large number below the orange bar \"museum\".")

    input := getConsoleInput()
    i, err := strconv.Atoi(input)
    if err != nil {
        fmt.Println("You did not enter a number. Please try again.")
        return requestInstitutionId(instanceLink)
    }

    output, validationErr := configloader.ValidateInstitutionId(i, instanceLink)
    if validationErr != nil {
        fmt.Println("This is not a valid institution ID. Please try again.")
        fmt.Print("----\nThe specific error is:\n")
        fmt.Println(validationErr)
        fmt.Print("----\n\n")
        return requestInstitutionId(instanceLink)
    }

    return output

}

// Prompts the user to enter their username.
func requestUsername() string {

    fmt.Println("\nPlease enter your user name in musdb (the name you use to log in with).")

    input := getConsoleInput()

    if input == "" {
        fmt.Println("You may not enter an empty user name. Please try again.")
        return requestUsername()
    }

    return input

}

// Prompts the user to enter a valid mail address until they do.
func requestMail() string {

    fmt.Println("\nPlease enter the email you set for your musdb account.")
    fmt.Println("Note that the spelling needs to be exactly the same as it is entered in musdb (e.g. in terms of capitalization).")

    input := getConsoleInput()

    output, validationErr := configloader.ValidateMail(input)
    if validationErr != nil {
        fmt.Println("This is not a valid mail address. Please try again.")
        fmt.Print("----\nThe specific error is:\n")
        fmt.Println(validationErr)
        fmt.Print("----\n\n")
        return requestMail()
    }

    return output

}

// Prompts the user to enter the webdav auth token.
func requestWebDavAuthToken() string {

    fmt.Println("\nPlease enter your WebDAV authentication token.")
    fmt.Println("You can generate a WebDAV authentication token on your account settings page in the tab \"WebDAV\".")

    input := getConsoleInput()

    if input == "" {
        fmt.Println("You may not enter an empty WebDAV authentication token. Please try again.")
        return requestWebDavAuthToken()
    }

    return input

}

// Prompts the user to enter a valid parser name until they do.
func requestParser() string {

    fmt.Println("\nPlease enter the parser with which you want to run imports.")
    fmt.Println("Parsers correspond with the input format. Available parsers are:")

    fmt.Println("")
    for _, parser := range(configloader.ListParsers()) {
        fmt.Println("- " + parser.Title)
    }
    fmt.Println("")

    input := getConsoleInput()

    output, validationErr := configloader.ValidateParser(input)
    if validationErr != nil {
        fmt.Println("This is not a valid parser name. Please enter one from the list. Please try again.")
        fmt.Print("----\nThe specific error is:\n")
        fmt.Println(validationErr)
        fmt.Print("----\n\n")
        return requestParser()
    }

    return output

}

// Prompts the user to enter a valid metadata folder.
func requestMetadataFolder() string {

    fmt.Println("\nPlease enter the full filepath of a directory for metadata files / exports from your local collection management system that should be automatically uploaded and imported.")
    fmt.Println("Note that the folder needs to exist.")

    input := getConsoleInput()

    output, validationErr := configloader.ValidateUploadDir(input)
    if validationErr != nil {
        fmt.Println("This is not a valid metadata folder. Please try again.")
        fmt.Print("----\nThe specific error is:\n")
        fmt.Println(validationErr)
        fmt.Print("----\n\n")
        return requestMetadataFolder()
    }

    return output

}

// Prompts the user to enter a valid media folder.
func requestMediaFolder() string {

    fmt.Println("\nPlease enter the full filepath of a directory for media files / exports from your local collection management system that should be automatically uploaded and imported.")
    fmt.Println("Note that the folder needs to exist.")

    input := getConsoleInput()

    output, validationErr := configloader.ValidateUploadDir(input)
    if validationErr != nil {
        fmt.Println("This is not a valid metadata folder. Please try again.")
        fmt.Print("----\nThe specific error is:\n")
        fmt.Println(validationErr)
        fmt.Print("----\n\n")
        return requestMediaFolder()
    }

    return output

}

// Prompts the user to say, whether they want to immediately publish the uploaded objects once imported.
func requestPublishOnImport() bool {

    fmt.Println("\nDo you want to immediately publish your objects, once they have been imported? If so, enter 'y', else, enter 'n'")

    input := getConsoleInput()

    if input == "y" {
        return true
    } else if input == "n" {
        return false
    } else {
        fmt.Println("You did not enter either y or n, please try again.")
        return requestPublishOnImport()
    }

}

// Queries the user for each of the relevant values for setup.
func RunManualSetup() {

    fmt.Println("Welcome to the setup of the museum-digital auto uploader")
    fmt.Println("This is the fully manual version of the setup, hence you will be asked for each value")

    config := configloader.MDWebDavUploaderConfig{}

    config.InstanceLink = requestInstanceLink()
    config.Username = requestUsername()
    config.InstitutionId = requestInstitutionId(config.InstanceLink)
    config.Mail = requestMail()
    config.WebDavAuthToken = requestWebDavAuthToken()
    config.Parser = requestParser()
    config.MetadataFolder = requestMetadataFolder()
    config.MediaFolder = requestMediaFolder()
    config.PublishOnImport = requestPublishOnImport()

    err := configloader.StoreConfigToFile(config, "")
    if err != nil {
        fmt.Println("\nFailed to store config")
        fmt.Println("Reason:")
        fmt.Println(err)
        panic("")
    }

    fmt.Println("Great! Your configuration has been stored. If you need to set further parser-specific settings, use --set-additional-setting. Else, use --upload.")

}

// Prints the current configuration.
func ShowCurrentConfig() {

    config, requiresSetup, err := configloader.LoadFromFile("")

    if requiresSetup == true {
        fmt.Println("Your config is incomplete. Please run the setup command before proceeding")
        return
    }

    if err != nil {
        fmt.Println("Another error occured:")
        fmt.Println(err)
        panic("")
    }

    fmt.Println(config)

}

// Runs the CLI workflow:
// - Check config validity

