package typescript

import (
	"io"
	"strings"

	. "code.justin.tv/spade/code-generator/internal"
)

type FieldDefinition struct {
	Identifier string
	Type       string
}

// SchemaFieldToProperty transform a schema field into a typescript type.
// e.g: "foo?: string" "foo: string" "foo: 1 | 2 | 3" ect ...
func SchemaFieldToProperty(field Field) FieldDefinition {
	d := FieldDefinition{Identifier: *field.Name, Type: "any"}

	if field.Type != nil {
		switch field.Type.Name {
		case "bool":
			d.Type = "boolean"
		case "long", "float", "timestamp":
			d.Type = "number"
		case "string":
			d.Type = "string"
		case "enum":
			{
				v := field.Type.Values
				if v == nil {
					break
				}

				// if the enum is not composed of only numbers
				// then wrap the enum values as a string literal
				// all enums values should be treated as the same kind
				// e.g if enum value is "a, b, 0" values will be "a" | "b" | "0"
				if AreAllNumbers(*v...) {
					d.Type = strings.Join(*v, " | ")
				} else {
					d.Type = strings.Join(ToStringLiterals(*v), " | ")
				}
			}
		}
	}

	if field.IsOptional() {
		d.Identifier = d.Identifier + "?"
	}

	return d
}

// StringsToRegexes transforms a slice of strings
// into a typescript array of regexes e.g: ["abc", "def"] -> "[/abc/, /def/]"
func StringsToRegexes(tokens []string) string {
	o := &strings.Builder{}
	o.WriteString("[")

	for i, token := range tokens {
		o.WriteString("/")
		o.WriteString(token)
		o.WriteString("/")

		if i < (len(tokens) - 1) {
			o.WriteString(",")
		}
	}

	o.WriteString("]")
	return o.String()
}

func WriteComment(o io.Writer, indent int, comment string) {
	comment = strings.TrimSuffix(comment, "\n")
	if !strings.Contains(comment, "\n") {
		P(o, strings.Repeat(" ", indent), "/** ", comment, " */")
		return
	}

	P(o, strings.Repeat(" ", indent), "/**")
	for _, msg := range strings.Split(comment, "\n") {
		P(o, strings.Repeat(" ", indent), "* ", msg)
	}

	P(o, strings.Repeat(" ", indent), "*/")
}
