package apidApigeeSync

import (
	"github.com/30x/apid-core"
	"github.com/apigee-labs/transicator/common"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"time"
	"net/http/httptest"
)

var _ = Describe("listener", func() {

	Context("sync", func() {

		var initializeContext = func() {
			testRouter = apid.API().Router()
			testServer = httptest.NewServer(testRouter)

			// set up mock server
			mockParms := MockParms{
				ReliableAPI:  true,
				ClusterID:    config.GetString(configApidClusterId),
				TokenKey:     config.GetString(configConsumerKey),
				TokenSecret:  config.GetString(configConsumerSecret),
				Scope:        "ert452",
				Organization: "att",
				Environment:  "prod",
			}
			testMock = Mock(mockParms, testRouter)

			config.Set(configProxyServerBaseURI, testServer.URL)
			config.Set(configSnapServerBaseURI, testServer.URL)
			config.Set(configChangeServerBaseURI, testServer.URL)
		}

		var restoreContext = func() {

			tokenManager.close()
			testServer.Close()

			config.Set(configProxyServerBaseURI, dummyConfigValue)
			config.Set(configSnapServerBaseURI, dummyConfigValue)
			config.Set(configChangeServerBaseURI, dummyConfigValue)

		}

		It("should succesfully bootstrap from clean slate", func(done Done) {
			log.Info("Starting sync tests...")
			initializeContext()

			// do not wipe DB after.  Lets use it
			wipeDBAferTest = false
			var lastSnapshot *common.Snapshot

			expectedSnapshotTables := common.ChangeList{
				Changes: []common.Change{common.Change{Table: "kms.company"},
							 common.Change{Table: "edgex.apid_cluster"},
							 common.Change{Table: "edgex.data_scope"}},
			}

			apid.Events().ListenFunc(ApigeeSyncEventSelector, func(event apid.Event) {

				if s, ok := event.(*common.Snapshot); ok {

					Expect(changesRequireDDLSync(expectedSnapshotTables)).To(BeFalse())

					//add apid_cluster and data_scope since those would present if this were a real scenario
					knownTables["kms.app_credential"] = true
					knownTables["kms.app_credential_apiproduct_mapper"] = true
					knownTables["kms.developer"] = true
					knownTables["kms.company_developer"] = true
					knownTables["kms.api_product"] = true
					knownTables["kms.app"] = true

					lastSnapshot = s

					for _, t := range s.Tables {
						switch t.Name {

						case "edgex.apid_cluster":
							Expect(t.Rows).To(HaveLen(1))
							r := t.Rows[0]
							var id string
							r.Get("id", &id)
							Expect(id).To(Equal("bootstrap"))

						case "edgex.data_scope":
							Expect(t.Rows).To(HaveLen(2))
							r := t.Rows[1] // get the non-cluster row

							var id, clusterID, env, org, scope string
							r.Get("id", &id)
							r.Get("apid_cluster_id", &clusterID)
							r.Get("env", &env)
							r.Get("org", &org)
							r.Get("scope", &scope)

							Expect(id).To(Equal("ert452"))
							Expect(scope).To(Equal("ert452"))
							Expect(clusterID).To(Equal("bootstrap"))
							Expect(env).To(Equal("prod"))
							Expect(org).To(Equal("att"))
						}
					}

				} else if cl, ok := event.(*common.ChangeList); ok {
					go func() { quitPollingChangeServer <- true }()
					// ensure that snapshot switched DB versions
					Expect(apidInfo.LastSnapshot).To(Equal(lastSnapshot.SnapshotInfo))
					expectedDB, err := dataService.DBVersion(lastSnapshot.SnapshotInfo)
					Expect(err).NotTo(HaveOccurred())
					Expect(getDB() == expectedDB).Should(BeTrue())

					Expect(cl.Changes).To(HaveLen(6))

					var tables []string
					for _, c := range cl.Changes {
						tables = append(tables, c.Table)
						Expect(c.NewRow).ToNot(BeNil())

						var tenantID string
						c.NewRow.Get("tenant_id", &tenantID)
						Expect(tenantID).To(Equal("ert452"))
					}

					Expect(tables).To(ContainElement("kms.app_credential"))
					Expect(tables).To(ContainElement("kms.app_credential_apiproduct_mapper"))
					Expect(tables).To(ContainElement("kms.developer"))
					Expect(tables).To(ContainElement("kms.company_developer"))
					Expect(tables).To(ContainElement("kms.api_product"))
					Expect(tables).To(ContainElement("kms.app"))

					events.ListenFunc(apid.EventDeliveredSelector, func(e apid.Event) {
						defer GinkgoRecover()

						// allow other handler to execute to insert last_sequence
						time.Sleep(50 * time.Millisecond)
						var seq string
						err = getDB().
							QueryRow("SELECT last_sequence FROM APID_CLUSTER LIMIT 1;").
							Scan(&seq)

						Expect(err).NotTo(HaveOccurred())
						Expect(seq).To(Equal(cl.LastSequence))

						restoreContext()
						close(done)
					})
				}
			})
			apid.InitializePlugins()
		}, 3)

		//this test has a dependency on the one above it.  Ideally we would write a test db to the disk instead
		It("should bootstrap from local DB if present", func(done Done) {

			/* postPluginInit event would have been emitted for the above test, clearing the list of registered plugins
		 	* In general, any additional sync tests (or any tests causing postInitPlugins to fire)
			 * will need to re-register the plugin
		 	*/
			initializeContext()
			apid.RegisterPlugin(initPlugin)

			expectedTables := common.ChangeList{
				Changes: []common.Change{common.Change{Table: "kms.company"},
							 common.Change{Table: "edgex.apid_cluster"},
							 common.Change{Table: "edgex.data_scope"}},
			}

			Expect(apidInfo.LastSnapshot).NotTo(BeEmpty())

			apid.Events().ListenFunc(ApigeeSyncEventSelector, func(event apid.Event) {

				if s, ok := event.(*common.Snapshot); ok {
					go func() { quitPollingChangeServer <- true }()
					//verify that the knownTables array has been properly populated from existing DB
					Expect(changesRequireDDLSync(expectedTables)).To(BeFalse())

					Expect(s.SnapshotInfo).Should(Equal(apidInfo.LastSnapshot))
					Expect(s.Tables).To(BeNil())

					restoreContext()
					close(done)
				}
			})
			apid.InitializePlugins()

		}, 3)

		It("should correctly identify non-proper subsets with respect to maps", func() {

			//test b proper subset of a
			Expect(changesHaveNewTables(map[string]bool{"a": true, "b": true},
				[]common.Change{common.Change{Table: "b"}},
			)).To(BeFalse())

			//test a == b
			Expect(changesHaveNewTables(map[string]bool{"a": true, "b": true},
				[]common.Change{common.Change{Table: "a"}, common.Change{Table: "b"}},
			)).To(BeFalse())

			//test b superset of a
			Expect(changesHaveNewTables(map[string]bool{"a": true, "b": true},
				[]common.Change{common.Change{Table: "a"}, common.Change{Table: "b"}, common.Change{Table: "c"}},
			)).To(BeTrue())

			//test b not subset of a
			Expect(changesHaveNewTables(map[string]bool{"a": true, "b": true},
				[]common.Change{common.Change{Table: "c"}},
			)).To(BeTrue())

			//test a empty
			Expect(changesHaveNewTables(map[string]bool{},
				[]common.Change{common.Change{Table: "a"}},
			)).To(BeTrue())

			//test b empty
			Expect(changesHaveNewTables(map[string]bool{"a": true, "b": true},
				[]common.Change{},
			)).To(BeFalse())

			//test b nil
			Expect(changesHaveNewTables(map[string]bool{"a": true, "b": true}, nil)).To(BeTrue())

			//test a nil
			Expect(changesHaveNewTables(nil,
				[]common.Change{common.Change{Table: "a"}},
			)).To(BeTrue())
		})

		// todo: disabled for now -
		// there is precondition I haven't been able to track down that breaks this test on occasion
		XIt("should process a new snapshot when change server requires it", func(done Done) {
			oldSnap := apidInfo.LastSnapshot
			apid.Events().ListenFunc(ApigeeSyncEventSelector, func(event apid.Event) {
				defer GinkgoRecover()

				if s, ok := event.(*common.Snapshot); ok {
					Expect(s.SnapshotInfo).NotTo(Equal(oldSnap))
					close(done)
				}
			})
			testMock.forceNewSnapshot()
		})
	})
})
