package main

import (
	"os"
	"path/filepath"
	"strings"
	"testing"
)

func TestGenerateGoFieldConstants_DedupesGeneratedFieldNames(t *testing.T) {
	root := t.TempDir()
	if err := os.MkdirAll(filepath.Join(root, "shared", "pkg", "constants"), 0755); err != nil {
		t.Fatalf("mkdir constants dir: %v", err)
	}

	ctx := &genContext{
		timestamp: "test",
		tables: []TableDefinition{
			{
				TableName: "Notification",
				Columns: []ColumnDef{
					{Name: "created_date", Type: "DATETIME"},
					{Name: "CreatedDate", Type: "DATETIME"},
				},
			},
		},
	}

	if err := generateGoFieldConstants(ctx, root); err != nil {
		t.Fatalf("generateGoFieldConstants: %v", err)
	}

	content, err := os.ReadFile(filepath.Join(root, "shared", "pkg", "constants", "z_generated_fields.go"))
	if err != nil {
		t.Fatalf("read generated fields: %v", err)
	}

	generated := string(content)
	if got := strings.Count(generated, "FieldNotification_CreatedDate"); got != 1 {
		t.Fatalf("FieldNotification_CreatedDate count = %d, want 1", got)
	}
	if !strings.Contains(generated, "FieldNotification_CreatedDate = \"created_date\"") {
		t.Fatalf("expected created_date mapping to be preserved, got:\n%s", generated)
	}
}

func TestGenerateGoStructs_DedupesGeneratedFieldNames(t *testing.T) {
	root := t.TempDir()
	if err := os.MkdirAll(filepath.Join(root, "shared", "pkg", "models"), 0755); err != nil {
		t.Fatalf("mkdir models dir: %v", err)
	}

	ctx := &genContext{
		timestamp: "test",
		tables: []TableDefinition{
			{
				TableName: "Notification",
				Columns: []ColumnDef{
					{Name: "created_date", Type: "DATETIME"},
					{Name: "CreatedDate", Type: "DATETIME"},
				},
			},
		},
	}

	if err := generateGoStructs(ctx, root); err != nil {
		t.Fatalf("generateGoStructs: %v", err)
	}

	content, err := os.ReadFile(filepath.Join(root, "shared", "pkg", "models", "z_generated.go"))
	if err != nil {
		t.Fatalf("read generated structs: %v", err)
	}

	generated := string(content)
	if got := strings.Count(generated, "CreatedDate time.Time"); got != 1 {
		t.Fatalf("CreatedDate field count = %d, want 1", got)
	}
	if !strings.Contains(generated, "CreatedDate time.Time `json:\"created_date\"`") {
		t.Fatalf("expected first logical field to win, got:\n%s", generated)
	}
}

func TestGenerateTypeScript_DedupesGeneratedFieldConstantKeys(t *testing.T) {
	root := t.TempDir()
	if err := os.MkdirAll(filepath.Join(root, "frontend", "src"), 0755); err != nil {
		t.Fatalf("mkdir frontend src dir: %v", err)
	}

	ctx := &genContext{
		timestamp: "test",
		tables: []TableDefinition{
			{
				TableName: "Notification",
				Columns: []ColumnDef{
					{Name: "created_date", Type: "DATETIME"},
					{Name: "CreatedDate", Type: "DATETIME"},
				},
			},
		},
	}

	if err := generateTypeScript(ctx, root); err != nil {
		t.Fatalf("generateTypeScript: %v", err)
	}

	content, err := os.ReadFile(filepath.Join(root, "frontend", "src", "generated-schema.ts"))
	if err != nil {
		t.Fatalf("read generated schema: %v", err)
	}

	generated := string(content)
	expectedBlock := "export const FIELDS_NOTIFICATION = {\n    CREATED_DATE: 'created_date',\n} as const;\n"
	if !strings.Contains(generated, expectedBlock) {
		t.Fatalf("expected created_date constant to be preserved, got:\n%s", generated)
	}
	expectedInterfaceBlock := "export interface Notification {\n    created_date: string;\n}\n"
	if !strings.Contains(generated, expectedInterfaceBlock) {
		t.Fatalf("expected notification interface to preserve created_date only, got:\n%s", generated)
	}
}

func TestGenerateGoStructs_HidesInternalLogicalFields(t *testing.T) {
	root := t.TempDir()
	if err := os.MkdirAll(filepath.Join(root, "shared", "pkg", "models"), 0755); err != nil {
		t.Fatalf("mkdir models dir: %v", err)
	}

	ctx := &genContext{
		timestamp: "test",
		tables: []TableDefinition{
			{
				TableName: "LayoutAssignment",
				Columns: []ColumnDef{
					{Name: "ObjectApiName", Type: "VARCHAR(191)"},
					{Name: "RouteSource", Type: "VARCHAR(32)", Nullable: true, LogicalType: "internal"},
				},
			},
		},
	}

	if err := generateGoStructs(ctx, root); err != nil {
		t.Fatalf("generateGoStructs: %v", err)
	}

	content, err := os.ReadFile(filepath.Join(root, "shared", "pkg", "models", "z_generated.go"))
	if err != nil {
		t.Fatalf("read generated structs: %v", err)
	}

	generated := string(content)
	if !strings.Contains(generated, "RouteSource *string `json:\"-\"`") {
		t.Fatalf("expected internal field to stay internal in generated Go structs, got:\n%s", generated)
	}
}

func TestGenerateTypeScript_SkipsInternalLogicalFields(t *testing.T) {
	root := t.TempDir()
	if err := os.MkdirAll(filepath.Join(root, "frontend", "src"), 0755); err != nil {
		t.Fatalf("mkdir frontend src dir: %v", err)
	}

	ctx := &genContext{
		timestamp: "test",
		tables: []TableDefinition{
			{
				TableName: "LayoutAssignment",
				Columns: []ColumnDef{
					{Name: "ObjectApiName", Type: "VARCHAR(191)"},
					{Name: "RouteSource", Type: "VARCHAR(32)", Nullable: true, LogicalType: "internal"},
				},
			},
		},
	}

	if err := generateTypeScript(ctx, root); err != nil {
		t.Fatalf("generateTypeScript: %v", err)
	}

	content, err := os.ReadFile(filepath.Join(root, "frontend", "src", "generated-schema.ts"))
	if err != nil {
		t.Fatalf("read generated schema: %v", err)
	}

	generated := string(content)
	if strings.Contains(generated, "ROUTE_SOURCE: 'RouteSource'") {
		t.Fatalf("expected internal field constant to be omitted, got:\n%s", generated)
	}
	if strings.Contains(generated, "RouteSource?: string;") {
		t.Fatalf("expected internal interface field to be omitted, got:\n%s", generated)
	}
}

func TestGenerateGoColumnLists_DedupesGeneratedFieldNames(t *testing.T) {
	root := t.TempDir()
	if err := os.MkdirAll(filepath.Join(root, "shared", "pkg", "constants"), 0755); err != nil {
		t.Fatalf("mkdir constants dir: %v", err)
	}

	ctx := &genContext{
		timestamp: "test",
		tables: []TableDefinition{
			{
				TableName: "Notification",
				Columns: []ColumnDef{
					{Name: "created_date", Type: "DATETIME"},
					{Name: "CreatedDate", Type: "DATETIME"},
				},
			},
		},
	}

	if err := generateGoColumnLists(ctx, root); err != nil {
		t.Fatalf("generateGoColumnLists: %v", err)
	}

	content, err := os.ReadFile(filepath.Join(root, "shared", "pkg", "constants", "z_generated_columns.go"))
	if err != nil {
		t.Fatalf("read generated columns: %v", err)
	}

	generated := string(content)
	expectedBlock := "\tColsNotification = []string{\n\t\tFieldNotification_CreatedDate,\n\t}\n"
	if !strings.Contains(generated, expectedBlock) {
		t.Fatalf("expected notification column list to preserve created_date only, got:\n%s", generated)
	}
}
