package commands

import (
	"bufio"
	"fmt"
	"os"
	"strings"

	"git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/common"
)

var (
	project        = common.NewProject()
	initHeaderText = `
This utility will walk you through creating a project.json file.
It only covers the most common items, and tries to guess sensible defaults.
	
Press ^C at any time to quit.
	`
	questionFormats    = map[bool]string{true: "%s: ", false: "%s: (%s) "}
	userInputQuestions = []struct {
		ask       string
		inputType string
		value     interface{}
		_default  interface{}
	}{
		{
			"project name",
			"",
			&project.Name,
			"",
		},
		{
			"author",
			"",
			&project.OwnerName,
			"",
		},
		{
			"version",
			"",
			&project.Version,
			"0.0.1",
		},
		{
			"description",
			"",
			&project.Description,
			"",
		},
		// {
		// 	"git repository",
		// 	"",
		// 	&project.Custom["go.package.repository"],
		// 	"",
		// },
	}
)

func initialize() (err error) {

	if common.FileExists("project.json") {
		err = fmt.Errorf("This folder already contains a project.")
		return
	}

	if err = readInitialUserInputData(); err != nil {
		return
	}

	if err = initializeProjectPropertires(); err != nil {
		return
	}

	if err = initializeBaseFilesAndSamples(); err != nil {
		return
	}
	if err = createRootDirectories(); err != nil {
		return
	}

	return
}

func readInitialUserInputData() (err error) {
	reader := bufio.NewReader(os.Stdin)
	fmt.Println(initHeaderText)
	for _, question := range userInputQuestions {
		args := []interface{}{question.ask}
		hasDefault := !common.IsEmpty(question._default)

		if hasDefault {
			args = append(args, question._default)
		}

		fmt.Printf(
			questionFormats[len(args) == 1],
			args...,
		)

		input, _ := reader.ReadString('\n')

		switch question.inputType {
		// case "int64":
		// case "float64":
		default:
			reference := question.value.(*string)
			input = strings.Replace(input, "\n", "", -1)
			if input == "" && hasDefault {
				input = question._default.(string)
			}
			*reference = input
		}
	}
	return
}

func initializeProjectPropertires() (err error) {
	project.ID = strings.ToLower(project.Name)
	return
}

func createRootDirectories() (err error) {

	three := []string{
		"build",
		EntitiesPath,
		ResourcesPath,
		EnvironmentPath,
		"include/go",
	}

	for index, path := range three {
		three[index] = basePathWithComplement(path)
	}

	err = common.Mkdir(0777, three...)

	return
}

func initializeBaseFilesAndSamples() (err error) {
	// Create main project description
	if err = common.WriteToJson(basePathWithComplement("project.json"), project); err != nil {
		return
	}

	if err = createEnvironmentFiles(); err != nil {
		return
	}

	if err = createQueriesFile(); err != nil {
		return
	}

	if err = createCommonFile(); err != nil {
		return
	}

	return
}

func createEnvironmentFiles() (err error) {

	var (
		environment = common.Environment{
			"APP_ADDRS": {
				Default:     "",
				Required:    true,
				Description: "Server address will listen for requests.",
			},
		}
		production = common.Environment{}
		test       = common.Environment{}
	)

	// Create main project description
	if err = common.WriteToJson(basePathWithComplement("env/environment.json"), environment); err != nil {
		return
	}

	if err = common.WriteToJson(basePathWithComplement("env/environment.prod.json"), production); err != nil {
		return
	}

	if err = common.WriteToJson(basePathWithComplement("env/environment.prod.json"), test); err != nil {
		return
	}
	return
}

func createCommonFile() (err error) {
	commonProperties := `
	{
		"commonParams": {
			"userId": {
				"id": "userId",
				"type": "string",
				"description": "Identificação do usuário que esta realizando a consulta.",
				"default": "me",
				"required": true,
				"location": "path"
			},
			"resource": {
				"id": "resource",
				"type": "string",
				"description": "Identificação do recurso do conjunto de regras de acesso.",
				"required": true,
				"location": "path"
			},
			"id": {
				"id": "id",
				"type": "string",
				"description": "Identificação da conta de usuário consultado.",
				"required": true,
				"location": "path"
			},
			"fields": {
				"id": "fields",
				"type": "string",
				"description": "Identifica um subconjunto de campos do modelo.",
				"required": false,
				"location": "query"
			},
			"includeInTrash": {
				"id": "includeInTrash",
				"type": "bool",
				"description": "Especifica se a consulta deve levar em consideração os registros deletados.",
				"required": false,
				"location": "query",
				"accept": [
					"true"
				]
			},
			"format": {
				"id": "format",
				"type": "string",
				"description": "Especifica configurações de campos predefinidas.",
				"required": false,
				"location": "query",
				"accept": [
					"minimal",
					"full"
				]
			},
			"maxResults": {
				"id": "maxResults",
				"type": "int",
				"description": "Identifica a quantidade de itens retornados da consulta.",
				"required": false,
				"location": "query"
			},
			"q": {
				"id": "q",
				"type": "string",
				"description": "Filtra as entidades de acordo com o criterio.",
				"required": false,
				"location": "query"
			},
			"nextPageToken": {
				"id": "nextPageToken",
				"type": "string",
				"description": "Token para consultar a proxima pagina contendo a lista de resultados.",
				"required": false,
				"location": "query"
			}
		}
	}`

	if err = common.FilePutContents(
		basePathWithComplement("common.json"),
		commonProperties,
		0777,
	); err != nil {
		return
	}
	return
}

func createQueriesFile() (err error) {
	template := `
	{
		"common": {
			"@mongo.empty": "{}",
			"@mongo.undelete": "{\"_id\":{\"$oid\":\"{{.id}}\"}}",
			"@mongo.listWithACL": "{\"$and\":[{ \"permissions.user._id\": \"{{.user}}\", \"deleted\": {{._deleted_}}},{{._transclude_}}]}",
			"@mongo.getWithACL": "{\"_id\":{\"$oid\":\"{{.id}}\"},\"permissions.user._id\":\"{{.user}}\",\"deleted\": {{._deleted_}}}",
			"@mongo.list": "{\"$and\":[{ \"deleted\": {{._deleted_}}},{{._transclude_}}]}",
			"@mongo.get": "{\"_id\":{\"$oid\":\"{{.id}}\"},\"deleted\": {{._deleted_}}}"
		},
		"queries": {}
	}`

	err = common.FilePutContents(
		basePathWithComplement("queries.json"),
		template,
		0777,
	)
	return
}
