package orgsso

import (
	"context"
	"time"

	"github.com/tidbcloud/account/idl/pbgen/proto/central"
	"github.com/tidbcloud/account/internel/dao/entity"
	domainsvc "github.com/tidbcloud/account/internel/svc/domain"
	usersvc "github.com/tidbcloud/account/internel/svc/user"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
	"google.golang.org/protobuf/types/known/emptypb"
)

type OrgDomainService struct {
	central.UnimplementedOrgDomainServiceServer
}

func NewOrgDomainService() central.OrgDomainServiceServer {
	return &OrgDomainService{}
}

func (s *OrgDomainService) AddDomain(ctx context.Context, req *central.AddDomainReq) (*central.OrgDomain, error) {
	tilog.Info(ctx, "OrgDomainService AddDomain", zap.Uint64("orgID", req.OrgId), zap.String("domain", req.DomainName))
	svc, _ := domainsvc.GetOrgDomainSvc()
	d, err := svc.AddDomain(ctx, req.OrgId, req.DomainName)
	if err != nil {
		return nil, err
	}
	return convOrgDomainToProto(d), nil
}

func (s *OrgDomainService) VerifyDomain(ctx context.Context, req *central.VerifyDomainReq) (*central.OrgDomain, error) {
	tilog.Info(ctx, "OrgDomainService VerifyDomain", zap.Uint64("orgID", req.OrgId), zap.Uint64("domainID", req.DomainId))
	svc, _ := domainsvc.GetOrgDomainSvc()
	d, err := svc.VerifyDomain(ctx, req.OrgId, req.DomainId)
	if err != nil {
		return nil, err
	}
	return convOrgDomainToProto(d), nil
}

func (s *OrgDomainService) ConfirmDomains(ctx context.Context, req *central.ConfirmDomainsReq) (*emptypb.Empty, error) {
	tilog.Info(ctx, "OrgDomainService ConfirmDomains", zap.Uint64("orgID", req.OrgId), zap.Uint64s("domainIDs", req.DomainIds))
	svc, _ := domainsvc.GetOrgDomainSvc()
	user, err := usersvc.GetUserFromContext(ctx)
	if err != nil {
		return nil, err
	}
	err = svc.ConfirmDomains(ctx, req.OrgId, req.DomainIds, user.Email)
	if err != nil {
		return nil, err
	}
	return &emptypb.Empty{}, nil
}

func (s *OrgDomainService) ListDomains(ctx context.Context, req *central.ListDomainsReq) (*central.ListDomainsRsp, error) {
	tilog.Info(ctx, "OrgDomainService ListDomains", zap.Uint64("orgID", req.OrgId))
	svc, _ := domainsvc.GetOrgDomainSvc()
	domains, err := svc.ListDomains(ctx, req.OrgId)
	if err != nil {
		return nil, err
	}
	rsp := &central.ListDomainsRsp{}
	for _, d := range domains {
		rsp.Domains = append(rsp.Domains, convOrgDomainToProto(&d))
	}
	return rsp, nil
}

func (s *OrgDomainService) DeleteDomain(ctx context.Context, req *central.DeleteDomainReq) (*emptypb.Empty, error) {
	tilog.Info(ctx, "OrgDomainService DeleteDomain", zap.Uint64("orgID", req.OrgId), zap.Uint64("domainID", req.DomainId))
	svc, _ := domainsvc.GetOrgDomainSvc()
	err := svc.DeleteDomain(ctx, req.OrgId, req.DomainId)
	if err != nil {
		return nil, err
	}
	return &emptypb.Empty{}, nil
}

func convOrgDomainToProto(d *entity.OrgDomain) *central.OrgDomain {
	p := &central.OrgDomain{
		Id:                d.ID.Uint64(),
		OrgId:             d.OrgID.Uint64(),
		DomainName:        d.DomainName,
		Status:            string(d.Status),
		VerificationToken: d.VerificationToken,
		Host:              domainsvc.VerificationDomainNamePrefix,
	}
	if d.VerifiedAt != nil {
		p.VerifiedAt = d.VerifiedAt.Format(time.RFC3339)
	}
	if d.ConfirmedAt != nil {
		p.ConfirmedAt = d.ConfirmedAt.Format(time.RFC3339)
	}
	p.ConfirmedBy = d.ConfirmedBy
	if d.ExpiresAt != nil {
		p.ExpiresAt = d.ExpiresAt.Format(time.RFC3339)
	}
	return p
}
