package service

import (
	"context"
	"fmt"

	caasmmodel "security-center-backend/internal/modules/caasm/model"
)

const defaultKillSwitchMessage = "CAASM kill switch is enabled; new sync execution is blocked"

type KillSwitchError struct {
	Message string
}

func (e *KillSwitchError) Error() string {
	if e == nil || e.Message == "" {
		return defaultKillSwitchMessage
	}
	return e.Message
}

func killSwitchMessage(stage string) string {
	if stage == "" {
		return defaultKillSwitchMessage
	}
	return fmt.Sprintf("%s (%s)", defaultKillSwitchMessage, stage)
}

func (s *CloudAccountService) isKillSwitchEnabled(ctx context.Context) (bool, error) {
	if s == nil || s.config == nil {
		return false, nil
	}
	return s.config.KillSwitchEnabled(ctx)
}

func (s *CloudAccountService) killSwitchError(message string) error {
	if message == "" {
		message = defaultKillSwitchMessage
	}
	return &KillSwitchError{Message: message}
}

func (s *CloudAccountService) blockIfKillSwitchEnabled(ctx context.Context, job *caasmmodel.SyncJob, accountID uint64, stage string) error {
	enabled, err := s.isKillSwitchEnabled(ctx)
	if err != nil {
		return err
	}
	if !enabled {
		return nil
	}
	if job != nil {
		s.failJobForKillSwitch(ctx, job, accountID, stage)
	}
	return s.killSwitchError(killSwitchMessage(stage))
}

func (s *CloudAccountService) failJobForKillSwitch(ctx context.Context, job *caasmmodel.SyncJob, accountID uint64, stage string) {
	if s == nil || s.jobs == nil || job == nil || job.ID == 0 {
		return
	}

	message := killSwitchMessage(stage)
	fields := map[string]interface{}{
		"status":        caasmmodel.SyncJobFailed,
		"error_message": message,
	}
	_ = s.jobs.UpdateFields(ctx, job.ID, fields)

	metadata := map[string]interface{}{
		"kill_switch": true,
	}
	if stage != "" {
		metadata["stage"] = stage
	}
	if accountID != 0 {
		metadata["cloud_account_id"] = accountID
	}
	s.recordJobEvent(ctx, job.ID, "warning", message, metadata)
}

func (s *CloudAccountService) failJobByIDForKillSwitch(ctx context.Context, syncJobID uint64, accountID uint64, stage string) error {
	if s == nil || s.jobs == nil || syncJobID == 0 {
		return nil
	}
	job, err := s.jobs.FindByID(ctx, syncJobID)
	if err != nil {
		return fmt.Errorf("find sync job for kill switch: %w", err)
	}
	s.failJobForKillSwitch(ctx, job, accountID, stage)
	return nil
}
