package virustotal

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"log/slog"
	"time"
)

const defaultScanTimeout = 60 * time.Second

// ScanResult is the outcome of a VirusTotal scan attempt.
type ScanResult struct {
	Status string // clean | skipped
}

// Scanner wraps Client with fail-open behavior on API errors.
type Scanner struct {
	client  *Client
	logger  *slog.Logger
	timeout time.Duration
}

func NewScanner(apiKey string, logger *slog.Logger) *Scanner {
	if logger == nil {
		logger = slog.Default()
	}
	return &Scanner{
		client:  NewClient(apiKey),
		logger:  logger,
		timeout: defaultScanTimeout,
	}
}

// ScanBytes scans file content. Returns ErrMalicious if detected.
// On VT unavailability, returns skipped (fail-open).
func (s *Scanner) ScanBytes(ctx context.Context, filename string, data []byte, sha256Hex string) (ScanResult, error) {
	if len(data) == 0 {
		return ScanResult{Status: "skipped"}, nil
	}
	if len(data) > maxUploadLimit {
		s.logger.Warn("virustotal scan skipped: file too large for VT", "filename", filename, "size", len(data))
		return ScanResult{Status: "skipped"}, nil
	}

	if sha256Hex == "" {
		sum := sha256.Sum256(data)
		sha256Hex = hex.EncodeToString(sum[:])
	}

	stats, found, err := s.client.lookupFile(ctx, sha256Hex)
	if err != nil {
		s.logger.Warn("virustotal lookup failed, skipping scan", "filename", filename, "error", err)
		return ScanResult{Status: "skipped"}, nil
	}
	if found {
		if statsMalicious(stats) {
			return ScanResult{}, ErrMalicious
		}
		return ScanResult{Status: "clean"}, nil
	}

	analysisID, err := s.client.uploadFile(ctx, data, safeFilename(filename))
	if err != nil {
		s.logger.Warn("virustotal upload failed, skipping scan", "filename", filename, "error", err)
		return ScanResult{Status: "skipped"}, nil
	}

	scanCtx, cancel := context.WithTimeout(ctx, s.timeout)
	defer cancel()

	stats, err = s.client.pollAnalysis(scanCtx, analysisID, s.timeout)
	if err != nil {
		s.logger.Warn("virustotal analysis failed, skipping scan", "filename", filename, "error", err)
		return ScanResult{Status: "skipped"}, nil
	}

	if statsMalicious(stats) {
		return ScanResult{}, ErrMalicious
	}
	return ScanResult{Status: "clean"}, nil
}

func safeFilename(name string) string {
	if name == "" {
		return "upload"
	}
	base := name
	if len(base) > 200 {
		base = base[:200]
	}
	return base
}

// SHA256Hex returns hex-encoded SHA-256 of data.
func SHA256Hex(data []byte) string {
	sum := sha256.Sum256(data)
	return hex.EncodeToString(sum[:])
}

// FormatAnalysisID is a helper for logging.
func FormatAnalysisID(id string) string {
	return fmt.Sprintf("vt:%s", id)
}
