package scanner

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
)

const (
	gotestwafTimeout = 120 * time.Second
	targetURL        = "https://git.sechpoint.app"
)

// RunGoTestWAF executes GoTestWAF scan against the target server.
// The report is saved to reports/ directory with the given reportName.
// Returns the raw output for AI analysis.
func RunGoTestWAF(ctx context.Context, projectRoot string, reportName string) (string, error) {
	binaryPath := filepath.Join(projectRoot, "gotestwaf")

	// Verify binary exists
	if _, err := os.Stat(binaryPath); os.IsNotExist(err) {
		return "", fmt.Errorf("GoTestWAF binary not found at %s", binaryPath)
	}

	reportsDir := filepath.Join(projectRoot, "reports")
	if err := os.MkdirAll(reportsDir, 0755); err != nil {
		return "", fmt.Errorf("failed to create reports directory: %w", err)
	}

	// Create context with timeout
	scanCtx, cancel := context.WithTimeout(ctx, gotestwafTimeout)
	defer cancel()

	cmd := exec.CommandContext(scanCtx, binaryPath,
		"--url", targetURL,
		"--configPath", "gotestwaf-config.yaml",
		"--testCasesPath", "testcases",
		"--maxIdleConns", "2",
		"--maxRedirects", "10",
		"--reportPath", reportsDir,
		"--reportName", reportName,
		"--reportFormat", "html",
		"--wafName", "generic",
		"--skipWAFBlockCheck",
		"--nonBlockedAsPassed",
		"--tlsVerify",
		"--noEmailReport",
		"--quiet",
	)

	cmd.Dir = projectRoot

	output, err := cmd.CombinedOutput()
	outputStr := string(output)

	if err != nil {
		if scanCtx.Err() == context.DeadlineExceeded {
			return outputStr, fmt.Errorf("GoTestWAF scan timed out after %v", gotestwafTimeout)
		}
		return outputStr, fmt.Errorf("GoTestWAF scan failed: %w", err)
	}

	return outputStr, nil
}

// FindMostCriticalSubdomain selects the most security-critical subdomain
// from a list of discovered subdomains. Prioritizes:
//   1. Subdomains with "api", "admin", "dashboard" in name
//   2. Subdomains vs root domain
//   3. First subdomain alphabetically as tiebreaker
func FindMostCriticalSubdomain(subdomains []string, originalDomain string) string {
	if len(subdomains) == 0 {
		return originalDomain
	}

	// Score each subdomain for "criticality"
	type scored struct {
		domain string
		score  int
	}

	var candidates []scored
	for _, s := range subdomains {
		score := 0
		lower := strings.ToLower(s)
		if strings.Contains(lower, "api") {
			score += 10
		}
		if strings.Contains(lower, "admin") {
			score += 8
		}
		if strings.Contains(lower, "dashboard") {
			score += 8
		}
		if strings.Contains(lower, "gateway") {
			score += 6
		}
		if strings.Contains(lower, "auth") {
			score += 6
		}
		if strings.Contains(lower, "console") {
			score += 5
		}
		if strings.Contains(lower, "dev") || strings.Contains(lower, "staging") {
			score += 4
		}
		if strings.Contains(lower, "app") {
			score += 2
		}
		// Prefer subdomains over root
		if strings.HasPrefix(s, "www.") {
			score += 1
		}
		if s != originalDomain && !strings.HasPrefix(s, "www.") {
			score += 3
		}
		candidates = append(candidates, scored{s, score})
	}

	// Find highest score
	best := candidates[0]
	for _, c := range candidates[1:] {
		if c.score > best.score || (c.score == best.score && c.domain < best.domain) {
			best = c
		}
	}

	return best.domain
}
