package approval

import (
	"context"
	"fmt"
	"os"
	"time"

	userv1 "github.com/tidbcloud/aisupport/packages/sdk-go/contracts/api/core-server/user/v1"
	apprent "github.com/tidbcloud/devops/entity/approval"
	"github.com/tidbcloud/devops/entity/event"
	"github.com/tidbcloud/devops/pkg/infra/clients/larkcli"
	"github.com/tidbcloud/devops/pkg/infra/config"
	"github.com/tidbcloud/devops/pkg/infra/consts"
	"github.com/tidbcloud/devops/pkg/infra/eventbus"
	"github.com/tidbcloud/devops/pkg/infra/utils/pointer"
	"github.com/tidbcloud/devops/pkg/service"
	"github.com/tidbcloud/devops/pkg/service/approval/api"
	"github.com/tidbcloud/devops/pkg/service/approval/approval"
	"github.com/tidbcloud/devops/pkg/service/approval/repo"
	"gopkg.in/yaml.v3"

	"github.com/go-logr/logr"
	"github.com/tidbcloud/pkgv2/db"
	"go.uber.org/dig"
)

type ServiceParam struct {
	dig.In

	Conf        *config.RootConfig
	Logger      logr.Logger
	DBProvider  db.TransProvider
	UserService userv1.UserServiceClient
	LarkClients *larkcli.LarkClient
	EventBus    *eventbus.EventBus
}

type ServiceResult struct {
	dig.Out

	API     api.ApprovalServiceAPI
	Service service.Service `group:"service"`
}

type svc struct {
	*service.BaseService

	conf     config.ApprovalServiceConfig
	userSvc  userv1.UserServiceClient
	dbp      db.TransProvider
	eventbus *eventbus.EventBus
	lark     *larkcli.LarkClient

	repo      repo.ApprovalRepo
	templates map[string]apprent.Template
}

func NewService(p ServiceParam) (ServiceResult, error) {
	base := service.NewBaseService("ApprovalService")
	var err error

	s := &svc{
		BaseService: base,

		conf:     p.Conf.Services.Approval,
		userSvc:  p.UserService,
		dbp:      p.DBProvider,
		eventbus: p.EventBus,
		lark:     p.LarkClients,
	}

	s.repo = repo.NewApprovalRepo(p.DBProvider)
	s.templates, err = LoadTemplatesFromFile(s.conf.TemplatesFilepath)

	return ServiceResult{API: s, Service: s}, err
}

func (s *svc) apprComps(ctx context.Context) approval.Components {
	return approval.Components{
		Repo:        s.repo,
		User:        s.userSvc,
		LarkClients: s.lark,
	}
}

func newEvent(ctx context.Context, id uint64, typ event.EventType) *event.ApprovalEvent {
	ev := &event.ApprovalEvent{
		BaseEvent: event.BaseEvent{
			ID:            id,
			OperatorEmail: consts.GetOperatorFromCtx(ctx, "unknown"),
			OperateAt:     pointer.Pointer(time.Now()),
			EventType:     typ,
		},
	}

	return ev
}

func LoadTemplatesFromFile(path string) (map[string]apprent.Template, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return nil, err
	}

	s := []apprent.Template{}
	err = yaml.Unmarshal(data, &s)
	if err != nil {
		return nil, err
	}

	m := map[string]apprent.Template{}
	for _, t := range s {
		if _, exist := m[t.ID]; exist {
			return nil, fmt.Errorf("duplicate template id: %s", t.ID)
		}
		m[t.ID] = t
	}

	return m, nil
}
