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"
)

func (s *AgentService) UpdateAuditLogSetting(
	ctx context.Context,
	req *apiv1.UpdateAuditLogSettingReq,
) (*apiv1.UpdateAuditLogSettingResp, error) {
	if err := validateUpdateAuditLogSettingReq(req); err != nil {
		return &apiv1.UpdateAuditLogSettingResp{Message: err.Error()}, err
	}

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

	cmds, err := buildUpdateAuditLogSettingCommands(req)
	if err != nil {
		return &apiv1.UpdateAuditLogSettingResp{Message: err.Error()}, err
	}

	if err := exec.ExecuteMulti(ctx, req.ClusterId, cmds); err != nil {
		return &apiv1.UpdateAuditLogSettingResp{Message: err.Error()}, err
	}

	return &apiv1.UpdateAuditLogSettingResp{Message: "success"}, nil
}

func validateUpdateAuditLogSettingReq(req *apiv1.UpdateAuditLogSettingReq) error {
	if req == nil {
		return fmt.Errorf("request is nil")
	}
	if req.Enabled == nil {
		return fmt.Errorf("enabled is required")
	}
	if req.Unredacted == nil {
		return fmt.Errorf("unredacted is required")
	}
	if err := validateAuditLogCommonFields(req.ClusterId, req.EncryptedUsername, req.EncryptedPassword); err != nil {
		return err
	}

	if _, err := sqlexec.NormalizeAuditLogFormat(req.Format); err != nil {
		return err
	}
	if req.MaxSizeMib < sqlexec.MinAuditLogMaxSizeMiB || req.MaxSizeMib > sqlexec.MaxAuditLogMaxSizeMiB {
		return fmt.Errorf("max_size_mib %d out of range [%d, %d]", req.MaxSizeMib, sqlexec.MinAuditLogMaxSizeMiB, sqlexec.MaxAuditLogMaxSizeMiB)
	}
	if req.MaxAgeSecond < sqlexec.MinAuditLogMaxAgeSecond || req.MaxAgeSecond > sqlexec.MaxAuditLogMaxAgeSecond {
		return fmt.Errorf("max_age_second %d out of range [%d, %d]", req.MaxAgeSecond, sqlexec.MinAuditLogMaxAgeSecond, sqlexec.MaxAuditLogMaxAgeSecond)
	}
	return nil
}

func buildUpdateAuditLogSettingCommands(req *apiv1.UpdateAuditLogSettingReq) ([]sqlexec.Command, error) {
	format, err := sqlexec.NormalizeAuditLogFormat(req.Format)
	if err != nil {
		return nil, err
	}
	enabled := req.GetEnabled()
	unredacted := req.GetUnredacted()

	setCommands := []sqlexec.Command{
		&sqlexec.SetAuditLogFilePathCommand{Path: sqlexec.DefaultAuditLogFilePath},
		&sqlexec.SetAuditLogRedactedCommand{Redacted: !unredacted},
		&sqlexec.SetAuditLogFormatCommand{Format: format},
		&sqlexec.SetAuditLogMaxFilesizeCommand{SizeMiB: req.MaxSizeMib},
		&sqlexec.SetAuditLogMaxLifetimeCommand{AgeSecond: req.MaxAgeSecond},
		&sqlexec.SetAuditLogReservedBackupsCommand{ReservedBackups: sqlexec.DefaultAuditLogReservedBackups},
	}

	if enabled {
		return append(setCommands, &sqlexec.SetAuditLogEnabledCommand{Enabled: true}), nil
	}

	disableFirst := []sqlexec.Command{
		&sqlexec.SetAuditLogEnabledCommand{Enabled: false},
		&sqlexec.RotateAuditLogCommand{},
	}
	return append(disableFirst, setCommands...), nil
}
