package store

import (
	_ "github.com/doug-martin/goqu/v9/dialect/mysql"

	"github.com/pingcap/test-infra/services/tcms/service"
	v2 "github.com/pingcap/test-infra/services/tcms/service/store/v2"
	"github.com/pingcap/test-infra/services/tcms/service/store/v2/ent"
	"github.com/pingcap/test-infra/services/tcms/utils"
	"github.com/pingcap/test-infra/services/tcms/utils/sql"
)

func NewDBClients(dsn string) (*sql.Database, *ent.Client) {
	db := sql.MustConnect(dsn)
	entCli := v2.EntClient(db.DB.DB)
	return db, entCli
}

type Store struct {
	DB  *sql.Database
	Ent *ent.Client

	User             service.UserService
	Token            service.TokenService
	Case             service.CaseService
	Plan             service.PlanService
	GitHubPlan       service.GitHubPlanService
	Trigger          service.TriggerService
	CaseExec         service.CaseExecutionService
	PlanExec         service.PlanExecutionService
	Testbed          service.TestbedService
	Summary          service.SummaryService
	RMS              service.RMSService
	ResourcePool     service.ResourcePoolService
	ResourceCohort   service.ResourceCohortService
	Triage           service.TriageService
	ResourceDuration service.ResourceDurationService
	TestbedSetup     service.TestbedSetupService
	SvcTask          service.SvcTaskService
	SvcTaskRun       service.SvcTaskRunService
	TestReport       service.ReportService
}

func New(config *utils.Config, rmsRPC service.RMSRPCService) *Store {
	db, ent := NewDBClients(config.DSN)

	user := new(userService)
	token := new(tokenService)
	case_ := new(caseService)
	plan := new(planService)
	githubPlan := new(githubPlanService)
	trigger := new(triggerService)
	caseExec := new(caseExecutionService)
	planExec := new(planExecutionService)
	testbed := new(testbedService)
	summary := new(summaryService)
	rms := new(rmsService)
	resourcePool := new(resourcePoolService)
	resourceCohort := new(resourceCohortService)
	triage := new(triageService)
	resourceDuration := new(resourceDurationService)
	testbedSetup := new(testbedSetupService)

	user.init(db)
	token.init(db)
	case_.init(db)
	plan.init(db, config, case_)
	planExec.init(db, plan)
	caseExec.init(db, planExec)
	trigger.init(db, plan, planExec)
	githubPlan.init(db, plan, trigger)
	testbed.init(ent, rmsRPC, planExec, resourcePool, resourceDuration)
	summary.init(db, triage, case_, caseExec, planExec, trigger)
	rms.init(db, rmsRPC, resourcePool)
	resourcePool.Init(db, rms)
	resourceCohort.init(db, resourcePool)
	triage.init(ent, planExec, caseExec, testbed)
	resourceDuration.init(ent, planExec, testbed, triage)
	testbedSetup.init(db)

	svcTaskService := NewSvcTaskService(db)

	return &Store{
		DB:               db,
		Ent:              ent,
		User:             user,
		Token:            token,
		Case:             case_,
		Plan:             plan,
		GitHubPlan:       githubPlan,
		Trigger:          trigger,
		CaseExec:         caseExec,
		PlanExec:         planExec,
		Testbed:          testbed,
		Summary:          summary,
		RMS:              rms,
		ResourcePool:     resourcePool,
		ResourceCohort:   resourceCohort,
		Triage:           triage,
		ResourceDuration: resourceDuration,
		TestbedSetup:     testbedSetup,
		SvcTask:          svcTaskService,
		SvcTaskRun:       NewSvcTaskRunService(db, svcTaskService, planExec, config.BaseURL),
		TestReport:       NewReporter(planExec, caseExec),
	}
}

func (s *Store) Shutdown() error {
	return s.DB.Close()
}
