package research_client_test

import (
	"context"
	"encoding/json"
	"os"
	"path/filepath"
	"reflect"
	"regexp"
	"runtime"
	"strings"
	"testing"

	"code.tnxs.net/vernonkeenan/lib/api/research/research_client/industry"
	"code.tnxs.net/vernonkeenan/lib/api/research/research_client/industry_companies"
	"code.tnxs.net/vernonkeenan/lib/api/research/research_client/industry_products"
	"code.tnxs.net/vernonkeenan/lib/api/research/research_client/industry_services"
	"code.tnxs.net/vernonkeenan/lib/api/research/research_models"
	openapiruntime "github.com/go-openapi/runtime"
	"github.com/go-openapi/strfmt"
)

type captureTransport struct {
	operation *openapiruntime.ClientOperation
}

func (transport *captureTransport) Submit(operation *openapiruntime.ClientOperation) (any, error) {
	return transport.SubmitContext(context.Background(), operation)
}

func (transport *captureTransport) SubmitContext(_ context.Context, operation *openapiruntime.ClientOperation) (any, error) {
	transport.operation = operation

	switch operation.ID {
	case "getIndustries":
		return industry.NewGetIndustriesOK(), nil
	case "postIndustries":
		return industry.NewPostIndustriesOK(), nil
	case "putIndustries":
		return industry.NewPutIndustriesOK(), nil
	case "getIndustryCompanies":
		return industry_companies.NewGetIndustryCompaniesOK(), nil
	case "postIndustryCompanies":
		return industry_companies.NewPostIndustryCompaniesOK(), nil
	case "getIndustryProducts":
		return industry_products.NewGetIndustryProductsOK(), nil
	case "postIndustryProducts":
		return industry_products.NewPostIndustryProductsOK(), nil
	case "getIndustryServices":
		return industry_services.NewGetIndustryServicesOK(), nil
	case "postIndustryServices":
		return industry_services.NewPostIndustryServicesOK(), nil
	default:
		panic("unexpected generated operation: " + operation.ID)
	}
}

func TestGeneratedIndustryOperationContract(t *testing.T) {
	type operationCall func(openapiruntime.ContextualTransport) error

	tests := []struct {
		name       string
		wantID     string
		wantMethod string
		wantPath   string
		call       operationCall
	}{
		{
			name:       "list industries",
			wantID:     "getIndustries",
			wantMethod: "GET",
			wantPath:   "/industries",
			call: func(transport openapiruntime.ContextualTransport) error {
				_, err := industry.New(transport, strfmt.Default).GetIndustries(industry.NewGetIndustriesParams(), nil)
				return err
			},
		},
		{
			name:       "create industry",
			wantID:     "postIndustries",
			wantMethod: "POST",
			wantPath:   "/industries",
			call: func(transport openapiruntime.ContextualTransport) error {
				_, err := industry.New(transport, strfmt.Default).PostIndustries(industry.NewPostIndustriesParams(), nil)
				return err
			},
		},
		{
			name:       "update industry",
			wantID:     "putIndustries",
			wantMethod: "PUT",
			wantPath:   "/industries",
			call: func(transport openapiruntime.ContextualTransport) error {
				_, err := industry.New(transport, strfmt.Default).PutIndustries(industry.NewPutIndustriesParams(), nil)
				return err
			},
		},
		{
			name:       "list industry companies",
			wantID:     "getIndustryCompanies",
			wantMethod: "GET",
			wantPath:   "/industrycompanies",
			call: func(transport openapiruntime.ContextualTransport) error {
				_, err := industry_companies.New(transport, strfmt.Default).GetIndustryCompanies(industry_companies.NewGetIndustryCompaniesParams(), nil)
				return err
			},
		},
		{
			name:       "create industry company",
			wantID:     "postIndustryCompanies",
			wantMethod: "POST",
			wantPath:   "/industrycompanies",
			call: func(transport openapiruntime.ContextualTransport) error {
				_, err := industry_companies.New(transport, strfmt.Default).PostIndustryCompanies(industry_companies.NewPostIndustryCompaniesParams(), nil)
				return err
			},
		},
		{
			name:       "list industry products",
			wantID:     "getIndustryProducts",
			wantMethod: "GET",
			wantPath:   "/industryproducts",
			call: func(transport openapiruntime.ContextualTransport) error {
				_, err := industry_products.New(transport, strfmt.Default).GetIndustryProducts(industry_products.NewGetIndustryProductsParams(), nil)
				return err
			},
		},
		{
			name:       "create industry product",
			wantID:     "postIndustryProducts",
			wantMethod: "POST",
			wantPath:   "/industryproducts",
			call: func(transport openapiruntime.ContextualTransport) error {
				_, err := industry_products.New(transport, strfmt.Default).PostIndustryProducts(industry_products.NewPostIndustryProductsParams(), nil)
				return err
			},
		},
		{
			name:       "list industry services",
			wantID:     "getIndustryServices",
			wantMethod: "GET",
			wantPath:   "/industryservices",
			call: func(transport openapiruntime.ContextualTransport) error {
				_, err := industry_services.New(transport, strfmt.Default).GetIndustryServices(industry_services.NewGetIndustryServicesParams(), nil)
				return err
			},
		},
		{
			name:       "create industry service",
			wantID:     "postIndustryServices",
			wantMethod: "POST",
			wantPath:   "/industryservices",
			call: func(transport openapiruntime.ContextualTransport) error {
				_, err := industry_services.New(transport, strfmt.Default).PostIndustryServices(industry_services.NewPostIndustryServicesParams(), nil)
				return err
			},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			transport := &captureTransport{}
			if err := test.call(transport); err != nil {
				t.Fatalf("generated client operation failed: %v", err)
			}
			if transport.operation == nil {
				t.Fatal("generated client did not submit an operation")
			}
			if transport.operation.ID != test.wantID {
				t.Errorf("operation ID = %q, want %q", transport.operation.ID, test.wantID)
			}
			if transport.operation.Method != test.wantMethod {
				t.Errorf("method = %q, want %q", transport.operation.Method, test.wantMethod)
			}
			if transport.operation.PathPattern != test.wantPath {
				t.Errorf("path = %q, want %q", transport.operation.PathPattern, test.wantPath)
			}
		})
	}
}

func TestIndustryServiceDoesNotInventHTML(t *testing.T) {
	serviceType := reflect.TypeOf(research_models.IndustryService{})
	if _, exists := serviceType.FieldByName("HTML"); exists {
		t.Fatal("IndustryService must not grow an HTML field absent from the authoritative contract")
	}

	productType := reflect.TypeOf(research_models.IndustryProduct{})
	if _, exists := productType.FieldByName("HTML"); !exists {
		t.Fatal("IndustryProduct must retain its authoritative HTML field")
	}

	payload, err := json.Marshal(research_models.IndustryService{ID: "industry-service-id"})
	if err != nil {
		t.Fatalf("marshal IndustryService: %v", err)
	}
	if strings.Contains(string(payload), "HTML") {
		t.Fatalf("IndustryService JSON invented an HTML field: %s", payload)
	}
}

func TestIndustryJunctionContractDoesNotInventUpdateOperations(t *testing.T) {
	interfaces := []struct {
		name string
		typ  reflect.Type
	}{
		{name: "IndustryCompany", typ: reflect.TypeOf((*industry_companies.ClientService)(nil)).Elem()},
		{name: "IndustryProduct", typ: reflect.TypeOf((*industry_products.ClientService)(nil)).Elem()},
		{name: "IndustryService", typ: reflect.TypeOf((*industry_services.ClientService)(nil)).Elem()},
	}

	for _, contract := range interfaces {
		for _, suffix := range []string{"", "Context"} {
			method := "Put" + contract.name + suffix
			if _, exists := contract.typ.MethodByName(method); exists {
				t.Errorf("%s client invented unsupported operation %s", contract.name, method)
			}
		}
	}
}

func TestGeneratedIndustrySurfaceHasNoSalesforceOrEmbeddedSecrets(t *testing.T) {
	_, testFile, _, ok := runtime.Caller(0)
	if !ok {
		t.Fatal("resolve test source path")
	}
	clientRoot := filepath.Dir(testFile)
	modelRoot := filepath.Join(clientRoot, "..", "research_models")
	targets := []string{
		filepath.Join(clientRoot, "industry"),
		filepath.Join(clientRoot, "industry_companies"),
		filepath.Join(clientRoot, "industry_products"),
		filepath.Join(clientRoot, "industry_services"),
		filepath.Join(modelRoot, "industry.go"),
		filepath.Join(modelRoot, "industry_company.go"),
		filepath.Join(modelRoot, "industry_product.go"),
		filepath.Join(modelRoot, "industry_service.go"),
	}
	credentialLiteral := regexp.MustCompile(`(?i)(api[_-]?key|password|secret)\s*[:=]\s*["'][^"']+["']`)

	for _, target := range targets {
		err := filepath.WalkDir(target, func(path string, entry os.DirEntry, walkErr error) error {
			if walkErr != nil {
				return walkErr
			}
			if entry.IsDir() || !strings.HasSuffix(path, ".go") || strings.HasSuffix(path, "_test.go") {
				return nil
			}

			content, err := os.ReadFile(path)
			if err != nil {
				return err
			}
			lower := strings.ToLower(string(content))
			for _, forbidden := range []string{"salesforce", "sf-gate", "go-force", "private key-----"} {
				if strings.Contains(lower, forbidden) {
					t.Errorf("%s contains forbidden boundary %q", path, forbidden)
				}
			}
			if credentialLiteral.Match(content) {
				t.Errorf("%s contains a credential-shaped literal", path)
			}
			return nil
		})
		if err != nil {
			t.Fatalf("scan generated contract target %s: %v", target, err)
		}
	}
}
