// Copyright 2025, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0

package main

import (
	"bytes"
	"fmt"
	"os"
	"reflect"
	"sort"
	"strings"

	"github.com/wavetermdev/waveterm/pkg/service"
	"github.com/wavetermdev/waveterm/pkg/tsgen"
	"github.com/wavetermdev/waveterm/pkg/util/utilfn"
	"github.com/wavetermdev/waveterm/pkg/wshrpc"
)

func generateTypesFile(tsTypesMap map[reflect.Type]string) error {
	fileName := "frontend/types/gotypes.d.ts"
	fmt.Fprintf(os.Stderr, "generating types file to %s\n", fileName)
	tsgen.GenerateWaveObjTypes(tsTypesMap)
	err := tsgen.GenerateServiceTypes(tsTypesMap)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error generating service types: %v\n", err)
		os.Exit(1)
	}
	err = tsgen.GenerateWshServerTypes(tsTypesMap)
	if err != nil {
		return fmt.Errorf("error generating wsh server types: %w", err)
	}
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "// Copyright 2025, Command Line Inc.\n")
	fmt.Fprintf(&buf, "// SPDX-License-Identifier: Apache-2.0\n\n")
	fmt.Fprintf(&buf, "// generated by cmd/generate/main-generatets.go\n\n")
	fmt.Fprintf(&buf, "declare global {\n\n")
	var keys []reflect.Type
	for key := range tsTypesMap {
		keys = append(keys, key)
	}
	sort.Slice(keys, func(i, j int) bool {
		iname, _ := tsgen.TypeToTSType(keys[i], tsTypesMap)
		jname, _ := tsgen.TypeToTSType(keys[j], tsTypesMap)
		return iname < jname
	})
	for _, key := range keys {
		// don't output generic types
		if strings.Contains(key.Name(), "[") {
			continue
		}
		tsCode := tsTypesMap[key]
		istr := utilfn.IndentString("    ", tsCode)
		fmt.Fprint(&buf, istr)
	}
	fmt.Fprintf(&buf, "}\n\n")
	fmt.Fprintf(&buf, "export {}\n")
	written, err := utilfn.WriteFileIfDifferent(fileName, buf.Bytes())
	if !written {
		fmt.Fprintf(os.Stderr, "no changes to %s\n", fileName)
	}
	return err
}

func generateServicesFile(tsTypesMap map[reflect.Type]string) error {
	fileName := "frontend/app/store/services.ts"
	var buf bytes.Buffer
	fmt.Fprintf(os.Stderr, "generating services file to %s\n", fileName)
	fmt.Fprintf(&buf, "// Copyright 2025, Command Line Inc.\n")
	fmt.Fprintf(&buf, "// SPDX-License-Identifier: Apache-2.0\n\n")
	fmt.Fprintf(&buf, "// generated by cmd/generate/main-generatets.go\n\n")
	fmt.Fprintf(&buf, "import * as WOS from \"./wos\";\n\n")
	orderedKeys := utilfn.GetOrderedMapKeys(service.ServiceMap)
	for _, serviceName := range orderedKeys {
		serviceObj := service.ServiceMap[serviceName]
		svcStr := tsgen.GenerateServiceClass(serviceName, serviceObj, tsTypesMap)
		fmt.Fprint(&buf, svcStr)
		fmt.Fprint(&buf, "\n")
	}
	written, err := utilfn.WriteFileIfDifferent(fileName, buf.Bytes())
	if !written {
		fmt.Fprintf(os.Stderr, "no changes to %s\n", fileName)
	}
	return err
}

func generateWshClientApiFile(tsTypeMap map[reflect.Type]string) error {
	fileName := "frontend/app/store/wshclientapi.ts"
	var buf bytes.Buffer
	declMap := wshrpc.GenerateWshCommandDeclMap()
	fmt.Fprintf(os.Stderr, "generating wshclientapi file to %s\n", fileName)
	fmt.Fprintf(&buf, "// Copyright 2025, Command Line Inc.\n")
	fmt.Fprintf(&buf, "// SPDX-License-Identifier: Apache-2.0\n\n")
	fmt.Fprintf(&buf, "// generated by cmd/generate/main-generatets.go\n\n")
	fmt.Fprintf(&buf, "import { WshClient } from \"./wshclient\";\n\n")
	orderedKeys := utilfn.GetOrderedMapKeys(declMap)
	fmt.Fprintf(&buf, "// WshServerCommandToDeclMap\n")
	fmt.Fprintf(&buf, "class RpcApiType {\n")
	for _, methodDecl := range orderedKeys {
		methodDecl := declMap[methodDecl]
		methodStr := tsgen.GenerateWshClientApiMethod(methodDecl, tsTypeMap)
		fmt.Fprint(&buf, methodStr)
		fmt.Fprintf(&buf, "\n")
	}
	fmt.Fprintf(&buf, "}\n\n")
	fmt.Fprintf(&buf, "export const RpcApi = new RpcApiType();\n")
	written, err := utilfn.WriteFileIfDifferent(fileName, buf.Bytes())
	if !written {
		fmt.Fprintf(os.Stderr, "no changes to %s\n", fileName)
	}
	return err
}

func main() {
	err := service.ValidateServiceMap()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error validating service map: %v\n", err)
		os.Exit(1)
	}
	tsTypesMap := make(map[reflect.Type]string)
	err = generateTypesFile(tsTypesMap)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error generating types file: %v\n", err)
		os.Exit(1)
	}
	err = generateServicesFile(tsTypesMap)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error generating services file: %v\n", err)
		os.Exit(1)
	}
	err = generateWshClientApiFile(tsTypesMap)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error generating wshserver file: %v\n", err)
		os.Exit(1)
	}
}
