package blueprint

import "testing"

func TestMergeIntoAddsPages(t *testing.T) {
	base := &Blueprint{
		Version: "1.0",
		Meta:    Meta{Name: "app", Slug: "demo"},
		Entities: []Entity{{
			Name: "item", Table: "item", Label: "Item", PrimaryKey: "id",
			Fields: []Field{{Name: "id", Label: "ID", Type: "string"}},
		}},
		Apis: Apis{
			BasePath: "/api/v1/apps/demo",
			Resources: []APIResource{{
				Entity: "item", Path: "/items", Operations: []string{"list"},
			}},
		},
		Pages: []Page{{ID: "item_list", Title: "列表", Route: "/items", Type: "list", Entity: "item"}},
	}
	incoming := &Blueprint{
		Entities: []Entity{{
			Name: "order", Table: "order", Label: "Order", PrimaryKey: "id",
			Fields: []Field{{Name: "id", Label: "ID", Type: "string"}},
		}},
		Apis: Apis{Resources: []APIResource{{
			Entity: "order", Path: "/orders", Operations: []string{"list", "import"},
		}}},
		Pages: []Page{{ID: "order_list", Title: "订单", Route: "/orders", Type: "list", Entity: "order"}},
	}
	res, err := MergeInto(base, incoming)
	if err != nil {
		t.Fatal(err)
	}
	if len(res.AddedPages) != 1 || res.AddedPages[0] != "order_list" {
		t.Fatalf("added pages: %+v", res.AddedPages)
	}
	if len(base.Pages) != 2 || len(base.Entities) != 2 {
		t.Fatalf("pages=%d entities=%d", len(base.Pages), len(base.Entities))
	}
}

func TestMergeIntoUpdatesExistingPageAndResource(t *testing.T) {
	base := &Blueprint{
		Apis: Apis{Resources: []APIResource{{
			Entity: "settlement_points", Path: "/settlement_points",
			Operations: []string{"list", "get", "create", "update", "delete"},
		}}},
		Pages: []Page{{
			ID: "record_list", Route: "/records", Type: "list", Entity: "settlement_points",
			Layout: &PageLayout{Actions: []string{"create", "edit", "delete"}},
		}},
	}
	incoming := &Blueprint{
		Apis: Apis{Resources: []APIResource{{
			Entity: "settlement_points", Path: "/settlement_points",
			Operations: []string{"list", "get", "create", "update", "delete", "import", "export"},
		}}},
		Pages: []Page{{
			ID: "record_list", Route: "/records", Type: "list", Entity: "settlement_points",
			Layout: &PageLayout{Actions: []string{"create", "edit", "delete", "import"}},
		}},
	}
	res, err := MergeInto(base, incoming)
	if err != nil {
		t.Fatal(err)
	}
	if len(res.AddedPages) != 0 {
		t.Fatalf("should not add pages: %+v", res.AddedPages)
	}
	if len(res.UpdatedResources) != 1 || res.UpdatedResources[0] != "settlement_points" {
		t.Fatalf("updated resources: %+v", res.UpdatedResources)
	}
	ops := base.Apis.Resources[0].Operations
	hasImport := false
	for _, op := range ops {
		if op == "import" {
			hasImport = true
		}
	}
	if !hasImport {
		t.Fatalf("ops missing import: %+v", ops)
	}
	acts := base.Pages[0].Layout.Actions
	hasAct := false
	for _, a := range acts {
		if a == "import" {
			hasAct = true
		}
	}
	if !hasAct {
		t.Fatalf("actions missing import: %+v", acts)
	}
}

func TestMergeIntoRejectsRouteConflictDifferentID(t *testing.T) {
	base := &Blueprint{
		Pages: []Page{{ID: "a", Route: "/a", Type: "list", Entity: "x"}},
	}
	incoming := &Blueprint{
		Pages: []Page{{ID: "b", Route: "/a", Type: "list", Entity: "x"}},
		Apis: Apis{Resources: []APIResource{{
			Entity: "x", Path: "/x", Operations: []string{"list", "import"},
		}}},
	}
	if _, err := MergeInto(base, incoming); err == nil {
		t.Fatal("expected route conflict error")
	}
}
