package lib

import (
	"encoding/json"
	"testing"
)

func TestOrgDataJSONMarshal(t *testing.T) {
	tests := []struct {
		name    string
		orgData OrgData
	}{
		{
			name: "single domain",
			orgData: OrgData{
				Name:         "Kaseya Corp",
				Domains:      []string{"kaseya.com"},
				Role:         "seller",
				Website:      "https://kaseya.com",
				Description:  "IT management software company",
				ContactName:  "Fred Voccola",
				ContactEmail: "fred@kaseya.com",
			},
		},
		{
			name: "multi domain",
			orgData: OrgData{
				Name:    "Datto Holdings",
				Domains: []string{"kaseya.com", "datto.com", "unitrends.com"},
				Role:    "buyer",
			},
		},
		{
			name: "minimal",
			orgData: OrgData{
				Name:    "Test Org",
				Domains: []string{"test.com"},
			},
		},
		{
			name: "ib role",
			orgData: OrgData{
				Name:    "Goldman Sachs",
				Domains: []string{"gs.com", "goldmansachs.com"},
				Role:    "ib",
			},
		},
		{
			name: "advisor role",
			orgData: OrgData{
				Name:    "Deloitte",
				Domains: []string{"deloitte.com"},
				Role:    "advisor",
			},
		},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			// Marshal
			data, err := json.Marshal(tc.orgData)
			if err != nil {
				t.Fatalf("Marshal failed: %v", err)
			}

			// Unmarshal
			var got OrgData
			if err := json.Unmarshal(data, &got); err != nil {
				t.Fatalf("Unmarshal failed: %v", err)
			}

			// Verify fields
			if got.Name != tc.orgData.Name {
				t.Errorf("Name: got %q, want %q", got.Name, tc.orgData.Name)
			}
			if len(got.Domains) != len(tc.orgData.Domains) {
				t.Errorf("Domains length: got %d, want %d", len(got.Domains), len(tc.orgData.Domains))
			}
			for i, d := range tc.orgData.Domains {
				if got.Domains[i] != d {
					t.Errorf("Domains[%d]: got %q, want %q", i, got.Domains[i], d)
				}
			}
			if got.Role != tc.orgData.Role {
				t.Errorf("Role: got %q, want %q", got.Role, tc.orgData.Role)
			}
			if got.Website != tc.orgData.Website {
				t.Errorf("Website: got %q, want %q", got.Website, tc.orgData.Website)
			}
			if got.Description != tc.orgData.Description {
				t.Errorf("Description: got %q, want %q", got.Description, tc.orgData.Description)
			}
			if got.ContactName != tc.orgData.ContactName {
				t.Errorf("ContactName: got %q, want %q", got.ContactName, tc.orgData.ContactName)
			}
			if got.ContactEmail != tc.orgData.ContactEmail {
				t.Errorf("ContactEmail: got %q, want %q", got.ContactEmail, tc.orgData.ContactEmail)
			}
		})
	}
}

func TestOrgDataJSONOmitEmpty(t *testing.T) {
	// Verify omitempty works for optional fields
	orgData := OrgData{
		Name:    "Minimal Org",
		Domains: []string{"minimal.com"},
	}

	data, err := json.Marshal(orgData)
	if err != nil {
		t.Fatalf("Marshal failed: %v", err)
	}

	// Parse as map to check field presence
	var m map[string]interface{}
	if err := json.Unmarshal(data, &m); err != nil {
		t.Fatalf("Unmarshal to map failed: %v", err)
	}

	// Required fields should be present
	if _, ok := m["name"]; !ok {
		t.Error("name should be present")
	}
	if _, ok := m["domains"]; !ok {
		t.Error("domains should be present")
	}

	// Optional fields with zero values should be omitted
	if v, ok := m["website"]; ok && v != "" {
		t.Error("website should be omitted when empty")
	}
	if v, ok := m["description"]; ok && v != "" {
		t.Error("description should be omitted when empty")
	}
}

func TestDealOrgDataJSONMarshal(t *testing.T) {
	tests := []struct {
		name        string
		dealOrgData DealOrgData
	}{
		{
			name: "seller with domain lock",
			dealOrgData: DealOrgData{
				OrgID:      "org-123",
				Role:       "seller",
				DomainLock: true,
			},
		},
		{
			name: "buyer without domain lock",
			dealOrgData: DealOrgData{
				OrgID:      "org-456",
				Role:       "buyer",
				DomainLock: false,
			},
		},
		{
			name: "ib role",
			dealOrgData: DealOrgData{
				OrgID:      "org-789",
				Role:       "ib",
				DomainLock: true,
			},
		},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			data, err := json.Marshal(tc.dealOrgData)
			if err != nil {
				t.Fatalf("Marshal failed: %v", err)
			}

			var got DealOrgData
			if err := json.Unmarshal(data, &got); err != nil {
				t.Fatalf("Unmarshal failed: %v", err)
			}

			if got.OrgID != tc.dealOrgData.OrgID {
				t.Errorf("OrgID: got %q, want %q", got.OrgID, tc.dealOrgData.OrgID)
			}
			if got.Role != tc.dealOrgData.Role {
				t.Errorf("Role: got %q, want %q", got.Role, tc.dealOrgData.Role)
			}
			if got.DomainLock != tc.dealOrgData.DomainLock {
				t.Errorf("DomainLock: got %v, want %v", got.DomainLock, tc.dealOrgData.DomainLock)
			}
		})
	}
}

func TestRequestDataJSONMarshal(t *testing.T) {
	tests := []struct {
		name string
		req  RequestData
	}{
		{
			name: "full request",
			req: RequestData{
				Title:          "Provide audited financial statements for the last 3 years",
				ItemNumber:     "1.3",
				Section:        "Financial",
				Description:    "Please provide audited P&L, balance sheet, and cash flow statements for FY2023, FY2024, FY2025.",
				Priority:       "high",
				Status:         "open",
				AssigneeID:     "user-123",
				AssigneeName:   "John Smith",
				DueDate:        "2026-03-15",
				BuyerComment:   "Need by end of week",
				SellerComment:  "Working on it",
				Tags:           []string{"financial", "urgent", "audit"},
				LinkedEntryIDs: []string{"entry-1", "entry-2"},
			},
		},
		{
			name: "minimal request",
			req: RequestData{
				Title:      "Basic info request",
				ItemNumber: "A-1",
				Section:    "General",
				Priority:   "medium",
				Status:     "open",
			},
		},
		{
			name: "answered request",
			req: RequestData{
				Title:          "Revenue breakdown by geography",
				ItemNumber:     "2.1",
				Section:        "Sales",
				Description:    "Provide revenue split by region (NA, EMEA, APAC)",
				Priority:       "low",
				Status:         "answered",
				LinkedEntryIDs: []string{"answer-123"},
			},
		},
		{
			name: "not applicable",
			req: RequestData{
				Title:       "Union contracts",
				ItemNumber:  "5.2",
				Section:     "HR",
				Description: "Provide all union agreements",
				Priority:    "low",
				Status:      "not_applicable",
			},
		},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			data, err := json.Marshal(tc.req)
			if err != nil {
				t.Fatalf("Marshal failed: %v", err)
			}

			var got RequestData
			if err := json.Unmarshal(data, &got); err != nil {
				t.Fatalf("Unmarshal failed: %v", err)
			}

			if got.Title != tc.req.Title {
				t.Errorf("Title: got %q, want %q", got.Title, tc.req.Title)
			}
			if got.ItemNumber != tc.req.ItemNumber {
				t.Errorf("ItemNumber: got %q, want %q", got.ItemNumber, tc.req.ItemNumber)
			}
			if got.Section != tc.req.Section {
				t.Errorf("Section: got %q, want %q", got.Section, tc.req.Section)
			}
			if got.Priority != tc.req.Priority {
				t.Errorf("Priority: got %q, want %q", got.Priority, tc.req.Priority)
			}
			if got.Status != tc.req.Status {
				t.Errorf("Status: got %q, want %q", got.Status, tc.req.Status)
			}
			if len(got.Tags) != len(tc.req.Tags) {
				t.Errorf("Tags length: got %d, want %d", len(got.Tags), len(tc.req.Tags))
			}
			if len(got.LinkedEntryIDs) != len(tc.req.LinkedEntryIDs) {
				t.Errorf("LinkedEntryIDs length: got %d, want %d", len(got.LinkedEntryIDs), len(tc.req.LinkedEntryIDs))
			}
		})
	}
}

func TestWorkstreamDataJSONMarshal(t *testing.T) {
	tests := []struct {
		name string
		ws   WorkstreamData
	}{
		{
			name: "with description",
			ws: WorkstreamData{
				Name:        "Financial Due Diligence",
				Description: "All financial information requests",
			},
		},
		{
			name: "minimal",
			ws: WorkstreamData{
				Name: "Legal",
			},
		},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			data, err := json.Marshal(tc.ws)
			if err != nil {
				t.Fatalf("Marshal failed: %v", err)
			}

			var got WorkstreamData
			if err := json.Unmarshal(data, &got); err != nil {
				t.Fatalf("Unmarshal failed: %v", err)
			}

			if got.Name != tc.ws.Name {
				t.Errorf("Name: got %q, want %q", got.Name, tc.ws.Name)
			}
			if got.Description != tc.ws.Description {
				t.Errorf("Description: got %q, want %q", got.Description, tc.ws.Description)
			}
		})
	}
}

func TestRoleHierarchyContainsSuperAdmin(t *testing.T) {
	// Verify super_admin is in the hierarchy and has the highest level
	saLevel, ok := RoleHierarchy[RoleSuperAdmin]
	if !ok {
		t.Fatal("super_admin should be in RoleHierarchy")
	}

	// super_admin should be higher than all other roles
	for role, level := range RoleHierarchy {
		if role != RoleSuperAdmin && level >= saLevel {
			t.Errorf("super_admin (%d) should be higher than %s (%d)", saLevel, role, level)
		}
	}
}
