package service

import (
	"context"
	"fmt"

	apiv1 "github.com/tidbcloud/cluster-service-ng/api/tidbcloud/cluster-agent/v1"

	"github.com/tidbcloud/cluster-service-ng/internal/cluster-agent/internal/sqlexec"
	"github.com/tidbcloud/cluster-service-ng/internal/cluster-agent/internal/utils"
)

type logRedactionQueryExecutor interface {
	Query(ctx context.Context, clusterID string, cmd sqlexec.QueryCommand) (sqlexec.QueryResult, error)
}

var newLogRedactionQueryExecutor = func(
	resolver utils.AddressResolver,
	auth sqlexec.DBAuth,
	tlsProvider sqlexec.TLSConfigProvider,
) logRedactionQueryExecutor {
	return sqlexec.NewDirectTiDBExecutor(resolver, auth, tlsProvider)
}

func (s *AgentService) UpdateLogRedactionPolicy(
	ctx context.Context,
	req *apiv1.UpdateLogRedactionPolicyReq,
) (*apiv1.UpdateLogRedactionPolicyResp, error) {
	if req == nil {
		err := fmt.Errorf("request is nil")
		return &apiv1.UpdateLogRedactionPolicyResp{Message: err.Error()}, err
	}
	// Scalar bool defaults to false on the wire, which would silently disable
	// redaction. Require the caller to set it explicitly via optional bool.
	if req.RedactLog == nil {
		err := fmt.Errorf("redact_log is required")
		return &apiv1.UpdateLogRedactionPolicyResp{Message: err.Error()}, err
	}
	if err := validateAuditLogCommonFields(req.ClusterId, req.EncryptedUsername, req.EncryptedPassword); err != nil {
		return &apiv1.UpdateLogRedactionPolicyResp{Message: err.Error()}, err
	}

	exec, err := s.newAuditLogDirectExecutor(ctx, req.EncryptedUsername, req.EncryptedPassword)
	if err != nil {
		return &apiv1.UpdateLogRedactionPolicyResp{Message: err.Error()}, err
	}

	cmds := []sqlexec.Command{&sqlexec.SetLogRedactionPolicyCommand{RedactLog: req.GetRedactLog()}}
	if err := exec.ExecuteMulti(ctx, req.ClusterId, cmds); err != nil {
		return &apiv1.UpdateLogRedactionPolicyResp{Message: err.Error()}, err
	}
	return &apiv1.UpdateLogRedactionPolicyResp{Message: "success"}, nil
}

func (s *AgentService) GetLogRedactionPolicy(
	ctx context.Context,
	req *apiv1.GetLogRedactionPolicyReq,
) (*apiv1.GetLogRedactionPolicyResp, error) {
	if req == nil {
		return nil, fmt.Errorf("request is nil")
	}
	if err := validateAuditLogCommonFields(req.ClusterId, req.EncryptedUsername, req.EncryptedPassword); err != nil {
		return nil, err
	}

	resolver, auth, tlsProvider, err := s.decryptDBCredentials(req.EncryptedUsername, req.EncryptedPassword)
	if err != nil {
		return nil, err
	}
	exec := newLogRedactionQueryExecutor(resolver, auth, tlsProvider)
	result, err := exec.Query(ctx, req.ClusterId, &sqlexec.GetLogRedactionPolicyCommand{})
	if err != nil {
		return nil, err
	}
	redact, err := sqlexec.ParseGetLogRedactionPolicyResult(result)
	if err != nil {
		return nil, err
	}
	return &apiv1.GetLogRedactionPolicyResp{RedactLog: redact}, nil
}
