/*
Copyright © 2025 Benny Powers <web@bennypowers.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package main

import (
	"fmt"
	"os"
	"path/filepath"
	"text/template"
	"time"
)

type AdapterType struct {
	Name          string // e.g., "AttributeMcpAdapter"
	ManifestType  string // e.g., "Attribute"
	InterfaceName string // e.g., "Attribute"
	Kind          string // e.g., "KindAttribute"
	MarkerMethod  string // e.g., "isEvent" (empty if none)
	HasType       bool   // whether it implements Typed interface
	HasDefault    bool   // whether it implements Defaultable interface
	HasValues     bool   // whether it implements Enumerable interface
	HasRequired   bool   // whether it has Required() method
	HasSyntax     bool   // whether it has CSS syntax
	HasInherits   bool   // whether it has CSS inherits
	HasInitial    bool   // whether it has CSS initial value
}

var adapterTypes = []AdapterType{
	{
		Name:          "AttributeMcpAdapter",
		ManifestType:  "Attribute",
		InterfaceName: "Attribute",
		Kind:          "KindAttribute",
		HasType:       true,
		HasDefault:    true,
		HasValues:     true,
		HasRequired:   true,
	},
	{
		Name:          "SlotMcpAdapter",
		ManifestType:  "Slot",
		InterfaceName: "Slot",
		Kind:          "KindSlot",
		MarkerMethod:  "isSlot",
	},
	{
		Name:          "EventMcpAdapter",
		ManifestType:  "Event",
		InterfaceName: "Event",
		Kind:          "KindEvent",
		MarkerMethod:  "isEvent",
		HasType:       true,
	},
	{
		Name:          "CssPropertyMcpAdapter",
		ManifestType:  "CssCustomProperty",
		InterfaceName: "CssProperty",
		Kind:          "KindCssProperty",
		HasSyntax:     true,
		HasInherits:   true,
		HasInitial:    true,
	},
	{
		Name:          "CssPartMcpAdapter",
		ManifestType:  "CssPart",
		InterfaceName: "CssPart",
		Kind:          "KindCssPart",
		MarkerMethod:  "isCssPart",
	},
	{
		Name:          "CssStateMcpAdapter",
		ManifestType:  "CssCustomState",
		InterfaceName: "CssState",
		Kind:          "KindCssState",
		MarkerMethod:  "isCssState",
	},
}

const templateString = `/*
Copyright © 2025 Benny Powers <web@bennypowers.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

// Code generated by mcp/tools/gen-adapters; DO NOT EDIT.
// Generated at: {{.Timestamp}}

package mcp

import (
	"encoding/json"
	M "bennypowers.dev/cem/manifest"
	"bennypowers.dev/cem/mcp/security"
)

{{range .Adapters}}
// {{.Name}} implements the {{.InterfaceName}} interface by embedding manifest.{{.ManifestType}}
type {{.Name}} struct {
	*M.{{.ManifestType}}
	guidelines []string
	examples   []string
}

func (a {{.Name}}) Kind() ItemKind {
	return {{.Kind}}
}

func (a {{.Name}}) Name() string {
	return a.{{.ManifestType}}.Name
}

func (a {{.Name}}) Description() string {
	return security.SanitizeDescription(a.{{.ManifestType}}.Description)
}

func (a {{.Name}}) Guidelines() []string {
	return a.guidelines
}

func (a {{.Name}}) Examples() []string {
	return a.examples
}

{{if .HasType}}
func (a {{.Name}}) Type() string {
	return getTypeString(a.{{.ManifestType}}.Type)
}
{{end}}

{{if .HasDefault}}
func (a {{.Name}}) Default() string {
	return a.{{.ManifestType}}.Default
}
{{end}}

{{if .HasValues}}
func (a {{.Name}}) Values() []string {
	return extractEnumValues(a.{{.ManifestType}}.Type)
}
{{end}}

{{if .HasRequired}}
func (a {{.Name}}) Required() bool {
	// This information is not available in the manifest structure
	return false
}
{{end}}

{{if .HasSyntax}}
func (a {{.Name}}) Syntax() string {
	return a.{{.ManifestType}}.Syntax
}
{{end}}

{{if .HasInherits}}
func (a {{.Name}}) Inherits() bool {
	// This information is not available in the manifest structure
	return false
}
{{end}}

{{if .HasInitial}}
func (a {{.Name}}) Initial() string {
	return a.{{.ManifestType}}.Default
}
{{end}}

{{if .MarkerMethod}}
func (a {{.Name}}) {{.MarkerMethod}}() {}
{{end}}

// MarshalJSON for {{.Name}}
func (a {{.Name}}) MarshalJSON() ([]byte, error) {
	j := itemJSON{
		Kind:        a.Kind(),
		Name:        a.Name(),
		Description: a.Description(),
		Guidelines:  a.Guidelines(),
		Examples:    a.Examples(),
		{{if .HasType}}Type:        stringPtr(a.Type()),{{end}}
		{{if .HasDefault}}Default:     stringPtr(a.Default()),{{end}}
		{{if .HasRequired}}Required:    boolPtr(a.Required()),{{end}}
		{{if .HasValues}}Values:      a.Values(),{{end}}
		{{if .HasSyntax}}Syntax:      stringPtr(a.Syntax()),{{end}}
		{{if .HasInherits}}Inherits:    boolPtr(a.Inherits()),{{end}}
		{{if .HasInitial}}Initial:     stringPtr(a.Initial()),{{end}}
	}
	return json.Marshal(j)
}

{{end}}

// Helper functions for pointer creation
func stringPtr(s string) *string {
	return &s
}

func boolPtr(b bool) *bool {
	return &b
}
`

func main() {
	tmpl, err := template.New("adapters").Parse(templateString)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error parsing template: %v\n", err)
		os.Exit(1)
	}

	data := struct {
		Timestamp string
		Adapters  []AdapterType
	}{
		Timestamp: time.Now().Format(time.RFC3339),
		Adapters:  adapterTypes,
	}

	// Get the current working directory
	wd, err := os.Getwd()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error getting working directory: %v\n", err)
		os.Exit(1)
	}

	// Find project root by looking for go.mod
	projectRoot := wd
	for {
		if _, err := os.Stat(filepath.Join(projectRoot, "go.mod")); err == nil {
			break
		}
		parent := filepath.Dir(projectRoot)
		if parent == projectRoot {
			// Reached filesystem root without finding go.mod
			fmt.Fprintf(os.Stderr, "Could not find project root (go.mod not found)\n")
			os.Exit(1)
		}
		projectRoot = parent
	}

	// Determine output file path
	outputPath := filepath.Join(projectRoot, "mcp", "adapters_generated.go")

	// Create the output file
	file, err := os.Create(outputPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error creating output file: %v\n", err)
		os.Exit(1)
	}
	defer func() {
		if err := file.Close(); err != nil {
			fmt.Fprintf(os.Stderr, "Error closing file: %v\n", err)
		}
	}()

	// Execute the template
	err = tmpl.Execute(file, data)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error executing template: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("Generated MCP adapters at: %s\n", outputPath)
}
