package main

import (
	"fmt"
	"io"
	"sort"
)

func emitTypes(w io.Writer, schemas []Schema, aliases []Alias) error {
	if _, err := fmt.Fprintln(w, typesHeader); err != nil {
		return err
	}
	for _, a := range sortAliases(aliases) {
		if _, err := fmt.Fprintf(w, "export type %s = %s;\n", a.Name, tsTypeExpr(a.Underlying)); err != nil {
			return err
		}
	}
	if len(aliases) > 0 {
		if _, err := fmt.Fprintln(w); err != nil {
			return err
		}
	}
	for _, s := range sortSchemas(schemas) {
		if _, err := fmt.Fprintf(w, "export interface %s {\n", s.Name); err != nil {
			return err
		}
		fields := append([]Field(nil), s.Fields...)
		sort.SliceStable(fields, func(i, j int) bool { return fields[i].JSONName < fields[j].JSONName })
		for _, f := range fields {
			optional := ""
			if f.Optional {
				optional = "?"
			}
			line := fmt.Sprintf("  %s%s: %s;\n", quoteIfNeeded(f.JSONName), optional, tsTypeExpr(f.Type))
			if _, err := fmt.Fprint(w, line); err != nil {
				return err
			}
		}
		if _, err := fmt.Fprintln(w, "}"); err != nil {
			return err
		}
		if _, err := fmt.Fprintln(w); err != nil {
			return err
		}
	}
	return nil
}

func tsTypeExpr(t TypeRef) string {
	switch t.Kind {
	case KindString:
		return "string"
	case KindBool:
		return "boolean"
	case KindInt, KindNumber:
		return "number"
	case KindAny, KindUnknown, KindRaw:
		return "unknown"
	case KindArray:
		return tsTypeExpr(*t.Element) + "[]"
	case KindMap:
		return "Record<" + tsTypeExpr(*t.Key) + ", " + tsTypeExpr(*t.Value) + ">"
	case KindRef:
		if t.Name == "nullable" {
			return tsTypeExpr(*t.Inner) + " | null"
		}
		return t.Name
	}
	return "unknown"
}

const typesHeader = `// Code generated by tools/openapigen. DO NOT EDIT.`
