package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/nexuscrm/shared/pkg/models"
)

func assertGeneratedPackLooksInstallable(t *testing.T, packRoot string) {
	t.Helper()
	raw, err := os.ReadFile(filepath.Join(packRoot, "pack.json"))
	if err != nil {
		t.Fatalf("read generated pack.json: %v", err)
	}
	var manifest packManifest
	dec := json.NewDecoder(bytes.NewReader(raw))
	dec.DisallowUnknownFields()
	if err := dec.Decode(&manifest); err != nil {
		t.Fatalf("parse generated pack.json: %v\n%s", err, string(raw))
	}
	if manifest.Name != applyPackName {
		t.Fatalf("generated pack name = %q, want %q", manifest.Name, applyPackName)
	}
	if len(manifest.Components) == 0 {
		t.Fatal("generated pack components = 0, want generated metadata components")
	}
	seen := map[string]struct{}{}
	for _, component := range manifest.Components {
		key := strings.TrimSpace(string(component.Kind)) + "\x00" + strings.TrimSpace(component.BusinessKey)
		if _, ok := seen[key]; ok {
			t.Fatalf("generated pack has duplicate component %s/%s", component.Kind, component.BusinessKey)
		}
		seen[key] = struct{}{}
		if strings.TrimSpace(string(component.Kind)) == "" {
			t.Fatalf("generated pack component has empty kind: %#v", component)
		}
		if strings.TrimSpace(component.BusinessKey) == "" {
			t.Fatalf("generated pack component has empty businessKey: %#v", component)
		}
		if strings.TrimSpace(component.Manageability) == "" {
			t.Fatalf("generated pack component has empty manageability: %#v", component)
		}
		payload, ref := generatedPackComponentPayload(t, packRoot, component)
		switch component.Kind {
		case componentKindStandardFlow:
			var flow models.FlowMetadata
			if err := json.Unmarshal(payload, &flow); err != nil {
				t.Fatalf("generated flow payload %s does not parse: %v\n%s", ref, err, string(payload))
			}
			if len(flow.ActionCalls) == 0 {
				t.Fatalf("generated flow payload %s has no actionCalls", ref)
			}
		case componentKind("email_template"):
			var template generatedEmailTemplatePayload
			if err := json.Unmarshal(payload, &template); err != nil {
				t.Fatalf("generated email_template payload %s does not parse: %v\n%s", ref, err, string(payload))
			}
			if strings.TrimSpace(template.DeveloperName) == "" {
				t.Fatalf("generated email_template payload %s has empty developerName", ref)
			}
		default:
			t.Fatalf("generated pack component kind %q is not expected for WorkflowAlert migration output", component.Kind)
		}
	}
}

func generatedPackComponentPayload(t *testing.T, packRoot string, component manifestComponent) ([]byte, string) {
	t.Helper()
	if len(component.Payload) > 0 {
		return append([]byte(nil), component.Payload...), "pack.json inline payload"
	}
	componentPath := strings.TrimSpace(component.Path)
	if componentPath == "" {
		t.Fatalf("component %s/%s has neither payload nor path", component.Kind, component.BusinessKey)
	}
	payloadPath := filepath.Join(packRoot, filepath.FromSlash(componentPath))
	payloadAbs, err := filepath.Abs(payloadPath)
	if err != nil {
		t.Fatalf("resolve generated component payload %q: %v", componentPath, err)
	}
	rootAbs, err := filepath.Abs(packRoot)
	if err != nil {
		t.Fatalf("resolve generated pack root: %v", err)
	}
	if !verifyZeroPathWithinDir(rootAbs, payloadAbs) {
		t.Fatalf("component path escapes generated pack root: %s", componentPath)
	}
	payload, err := os.ReadFile(payloadAbs)
	if err != nil {
		t.Fatalf("read generated component payload %q: %v", componentPath, err)
	}
	return payload, fmt.Sprintf("%s:%s", component.Kind, componentPath)
}
