package bot

import (
	"context"
	"fmt"
	"log"

	"github.com/mymmrac/telego"
	"github.com/mymmrac/telego/telegoutil"
	"github.com/salvacybersec/keyhunter/pkg/engine"
	"github.com/salvacybersec/keyhunter/pkg/scheduler"
)

// NotifyNewFindings sends a notification to all subscribers about scan results.
// It returns the number of messages successfully sent and any per-subscriber errors.
// If FindingCount is 0 and Error is nil, no notification is sent (silent success).
// If Error is non-nil, an error notification is sent instead.
func (b *Bot) NotifyNewFindings(result scheduler.JobResult) (int, []error) {
	// No notification for zero-finding success.
	if result.FindingCount == 0 && result.Error == nil {
		return 0, nil
	}

	subs, err := b.cfg.DB.ListSubscribers()
	if err != nil {
		log.Printf("notify: listing subscribers: %v", err)
		return 0, []error{fmt.Errorf("listing subscribers: %w", err)}
	}
	if len(subs) == 0 {
		return 0, nil
	}

	var msg string
	if result.Error != nil {
		msg = formatErrorNotification(result)
	} else {
		msg = formatNotification(result)
	}

	var sent int
	var errs []error
	for _, sub := range subs {
		if b.bot == nil {
			// No telego bot (test mode) -- count as would-send.
			continue
		}
		params := telegoutil.Message(telego.ChatID{ID: sub.ChatID}, msg)
		if _, sendErr := b.bot.SendMessage(context.Background(), params); sendErr != nil {
			log.Printf("notify: sending to chat %d: %v", sub.ChatID, sendErr)
			errs = append(errs, fmt.Errorf("chat %d: %w", sub.ChatID, sendErr))
			continue
		}
		sent++
	}

	return sent, errs
}

// NotifyFinding sends a real-time notification about an individual finding
// to all subscribers. The key is always masked.
func (b *Bot) NotifyFinding(finding engine.Finding) (int, []error) {
	subs, err := b.cfg.DB.ListSubscribers()
	if err != nil {
		log.Printf("notify: listing subscribers: %v", err)
		return 0, []error{fmt.Errorf("listing subscribers: %w", err)}
	}
	if len(subs) == 0 {
		return 0, nil
	}

	msg := formatFindingNotification(finding)

	var sent int
	var errs []error
	for _, sub := range subs {
		if b.bot == nil {
			continue
		}
		params := telegoutil.Message(telego.ChatID{ID: sub.ChatID}, msg)
		if _, sendErr := b.bot.SendMessage(context.Background(), params); sendErr != nil {
			log.Printf("notify: sending finding to chat %d: %v", sub.ChatID, sendErr)
			errs = append(errs, fmt.Errorf("chat %d: %w", sub.ChatID, sendErr))
			continue
		}
		sent++
	}

	return sent, errs
}

// formatNotification builds the notification message for a successful scan
// with findings.
func formatNotification(result scheduler.JobResult) string {
	return fmt.Sprintf(
		"New findings from scheduled scan!\n\nJob: %s\nNew keys found: %d\nDuration: %s\n\nUse /stats for details.",
		result.JobName,
		result.FindingCount,
		result.Duration,
	)
}

// formatErrorNotification builds the notification message for a scan that
// encountered an error.
func formatErrorNotification(result scheduler.JobResult) string {
	return fmt.Sprintf(
		"Scheduled scan error\n\nJob: %s\nDuration: %s\nError: %v",
		result.JobName,
		result.Duration,
		result.Error,
	)
}

// formatFindingNotification builds the notification message for an individual
// finding. Always uses the masked key.
func formatFindingNotification(finding engine.Finding) string {
	return fmt.Sprintf(
		"New key detected!\nProvider: %s\nKey: %s\nSource: %s:%d\nConfidence: %s",
		finding.ProviderName,
		finding.KeyMasked,
		finding.Source,
		finding.LineNumber,
		finding.Confidence,
	)
}
