<?php

declare(strict_types=1);

use Phinx\Seed\AbstractSeed;

/**
 * Seeds three baseline policies — paranoid (most aggressive), moderate
 * (balanced), strict (highest signal-to-noise) — with thresholds across all
 * five default categories.
 *
 * Naming nuance: "strict" here means "strictly only block when confidence is
 * high" (high threshold = fewer entries) while "paranoid" means "block at the
 * slightest hint" (low threshold = many entries). This mirrors operator usage
 * where "strict" describes the inclusion bar, not the resulting blocklist size.
 *
 * Idempotent: skips policies and threshold rows that already exist.
 */
final class DefaultPoliciesSeeder extends AbstractSeed
{
    /**
     * @return array<class-string<\Phinx\Seed\AbstractSeed>>
     */
    public function getDependencies(): array
    {
        return ['DefaultCategoriesSeeder'];
    }

    public function run(): void
    {
        $policiesSpec = [
            'strict' => [
                'description' => 'Conservative: block only IPs with strong signal across categories.',
                'thresholds' => [
                    'brute_force' => '2.5000',
                    'spam' => '2.5000',
                    'scanner' => '2.5000',
                    'malware_c2' => '2.5000',
                    'web_attack' => '2.5000',
                ],
            ],
            'moderate' => [
                'description' => 'Balanced: block IPs with moderate accumulated abuse signal.',
                'thresholds' => [
                    'brute_force' => '1.0000',
                    'spam' => '1.0000',
                    'scanner' => '1.0000',
                    'malware_c2' => '1.0000',
                    'web_attack' => '1.0000',
                ],
            ],
            'paranoid' => [
                'description' => 'Aggressive: block on faint signal; expect more false positives.',
                'thresholds' => [
                    'brute_force' => '0.3000',
                    'spam' => '0.3000',
                    'scanner' => '0.3000',
                    'malware_c2' => '0.3000',
                    'web_attack' => '0.3000',
                ],
            ],
        ];

        $existingPolicies = $this->fetchAll('SELECT id, name FROM policies');
        $policyByName = [];
        foreach ($existingPolicies as $row) {
            $policyByName[$row['name']] = (int) $row['id'];
        }

        $insertPolicies = [];
        foreach ($policiesSpec as $name => $spec) {
            if (isset($policyByName[$name])) {
                continue;
            }
            $insertPolicies[] = [
                'name' => $name,
                'description' => $spec['description'],
                'include_manual_blocks' => 1,
            ];
        }

        if ($insertPolicies !== []) {
            $this->table('policies')->insert($insertPolicies)->save();
        }

        // Re-fetch to include newly inserted policies.
        $allPolicies = $this->fetchAll('SELECT id, name FROM policies');
        $policyByName = [];
        foreach ($allPolicies as $row) {
            $policyByName[$row['name']] = (int) $row['id'];
        }

        $allCategories = $this->fetchAll('SELECT id, slug FROM categories');
        $categoryBySlug = [];
        foreach ($allCategories as $row) {
            $categoryBySlug[$row['slug']] = (int) $row['id'];
        }

        $existingThresholds = $this->fetchAll('SELECT policy_id, category_id FROM policy_category_thresholds');
        $existingPairs = [];
        foreach ($existingThresholds as $row) {
            $existingPairs[(int) $row['policy_id'] . ':' . (int) $row['category_id']] = true;
        }

        $thresholdRows = [];
        foreach ($policiesSpec as $name => $spec) {
            if (!isset($policyByName[$name])) {
                continue;
            }
            $policyId = $policyByName[$name];

            foreach ($spec['thresholds'] as $slug => $threshold) {
                if (!isset($categoryBySlug[$slug])) {
                    continue;
                }
                $categoryId = $categoryBySlug[$slug];
                $key = $policyId . ':' . $categoryId;
                if (isset($existingPairs[$key])) {
                    continue;
                }
                $thresholdRows[] = [
                    'policy_id' => $policyId,
                    'category_id' => $categoryId,
                    'threshold' => $threshold,
                ];
            }
        }

        if ($thresholdRows !== []) {
            $this->table('policy_category_thresholds')->insert($thresholdRows)->save();
        }
    }
}
