<?php
/**
 * AI Monitor Ignore Rules - admin management page.
 * Root-only (enforced by permission_manager.php). Lets the operator add,
 * edit, disable, and delete rules that suppress AI Monitor findings before
 * they become customer-visible issues.
 */

if (!defined('AUTH_USER') || AUTH_USER !== 'root') {
    header('Location: index.php?page=dashboard');
    exit;
}

require_once('/docker/whp/web/libs/mysqlmgmt.php');

$message = '';
$message_type = '';

$mysql = new mysqlmgmt();
$db = $mysql->getMySQLConnection();
if (!$db) {
    echo '<div class="alert alert-danger">Database connection failed.</div>';
    return;
}
$db->exec("USE whp");

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!validate_csrf_token()) {
        $message = 'Invalid or expired CSRF token. Please refresh and try again.';
        $message_type = 'danger';
    } else {
        $post_action = $_POST['action'] ?? '';
        try {
            switch ($post_action) {

                case 'create_rule': {
                    $scope    = $_POST['scope'] ?? '';
                    $username = trim($_POST['username'] ?? '');
                    $site_id  = isset($_POST['site_id']) && $_POST['site_id'] !== '' ? (int)$_POST['site_id'] : null;
                    $reason   = trim($_POST['reason'] ?? '');

                    if (!in_array($scope, ['global','user','site'], true)) {
                        throw new Exception('Invalid scope.');
                    }
                    if ($reason === '') {
                        throw new Exception('Reason is required.');
                    }
                    if ($scope === 'user' && $username === '') {
                        throw new Exception('Username is required for user-scoped rules.');
                    }
                    if ($scope === 'site' && !$site_id) {
                        throw new Exception('Site is required for site-scoped rules.');
                    }
                    if ($scope !== 'user') $username = null;
                    if ($scope !== 'site') $site_id = null;

                    $mc = trim($_POST['match_category'] ?? '');
                    $ms = trim($_POST['match_severity'] ?? '');
                    $mt = trim($_POST['match_title_substr'] ?? '');
                    $mr = trim($_POST['match_raw_regex'] ?? '');

                    if ($mc === '' && $ms === '' && $mt === '' && $mr === '') {
                        throw new Exception('At least one match field must be set (otherwise the rule would silence every finding in scope).');
                    }
                    if ($ms !== '' && !in_array($ms, ['critical','warning','info'], true)) {
                        throw new Exception('Invalid severity.');
                    }
                    if ($mr !== '') {
                        $test = '/' . str_replace('/', '\\/', $mr) . '/iu';
                        if (@preg_match($test, "sample log line 123 ERROR foo bar") === false) {
                            throw new Exception('Regex is malformed or unsupported.');
                        }
                    }

                    $stmt = $db->prepare("
                        INSERT INTO whp.ai_monitor_ignore_rules
                            (scope, username, site_id, match_category, match_severity,
                             match_title_substr, match_raw_regex, reason, enabled, created_by)
                        VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, ?)
                    ");
                    $stmt->execute([
                        $scope, $username, $site_id,
                        $mc !== '' ? $mc : null,
                        $ms !== '' ? $ms : null,
                        $mt !== '' ? $mt : null,
                        $mr !== '' ? $mr : null,
                        $reason, AUTH_USER,
                    ]);
                    $message = 'Rule created.';
                    $message_type = 'success';
                    break;
                }

                case 'toggle_rule': {
                    $id = (int)($_POST['id'] ?? 0);
                    if ($id) {
                        $db->prepare("UPDATE whp.ai_monitor_ignore_rules SET enabled = 1 - enabled WHERE id = ?")
                            ->execute([$id]);
                        $message = 'Rule toggled.';
                        $message_type = 'success';
                    }
                    break;
                }

                case 'delete_rule': {
                    $id = (int)($_POST['id'] ?? 0);
                    if ($id) {
                        $db->prepare("DELETE FROM whp.ai_monitor_ignore_rules WHERE id = ?")
                            ->execute([$id]);
                        $message = 'Rule deleted.';
                        $message_type = 'success';
                    }
                    break;
                }

                case 'update_rule': {
                    $id = (int)($_POST['id'] ?? 0);
                    if (!$id) {
                        throw new Exception('Missing rule id.');
                    }
                    $reason = trim($_POST['reason'] ?? '');
                    if ($reason === '') {
                        throw new Exception('Reason is required.');
                    }
                    $mc = trim($_POST['match_category'] ?? '');
                    $ms = trim($_POST['match_severity'] ?? '');
                    $mt = trim($_POST['match_title_substr'] ?? '');
                    $mr = trim($_POST['match_raw_regex'] ?? '');

                    if ($mc === '' && $ms === '' && $mt === '' && $mr === '') {
                        throw new Exception('At least one match field must be set.');
                    }
                    if ($ms !== '' && !in_array($ms, ['critical','warning','info'], true)) {
                        throw new Exception('Invalid severity.');
                    }
                    if ($mr !== '') {
                        $test = '/' . str_replace('/', '\\/', $mr) . '/iu';
                        if (@preg_match($test, "sample log line 123 ERROR foo bar") === false) {
                            throw new Exception('Regex is malformed or unsupported.');
                        }
                    }

                    $stmt = $db->prepare("
                        UPDATE whp.ai_monitor_ignore_rules
                        SET match_category = ?, match_severity = ?,
                            match_title_substr = ?, match_raw_regex = ?,
                            reason = ?
                        WHERE id = ?
                    ");
                    $stmt->execute([
                        $mc !== '' ? $mc : null,
                        $ms !== '' ? $ms : null,
                        $mt !== '' ? $mt : null,
                        $mr !== '' ? $mr : null,
                        $reason, $id,
                    ]);
                    $message = 'Rule updated.';
                    $message_type = 'success';
                    break;
                }
            }
        } catch (Throwable $e) {
            $message = htmlspecialchars($e->getMessage());
            $message_type = 'danger';
        }
    }
}

$filter_scope   = $_GET['filter_scope'] ?? '';
$filter_enabled = $_GET['filter_enabled'] ?? '';
$page_num       = max(1, (int)($_GET['p'] ?? 1));
$per_page       = 50;
$offset         = ($page_num - 1) * $per_page;

$where  = [];
$params = [];
if (in_array($filter_scope, ['global','user','site'], true)) {
    $where[]  = 'scope = ?';
    $params[] = $filter_scope;
}
if ($filter_enabled === '1' || $filter_enabled === '0') {
    $where[]  = 'enabled = ?';
    $params[] = (int)$filter_enabled;
}
$whereSql = $where ? ('WHERE ' . implode(' AND ', $where)) : '';

$countStmt = $db->prepare("SELECT COUNT(*) FROM whp.ai_monitor_ignore_rules {$whereSql}");
$countStmt->execute($params);
$total = (int)$countStmt->fetchColumn();
$total_pages = max(1, (int)ceil($total / $per_page));

$listStmt = $db->prepare("
    SELECT r.*, s.site_name, d.domain_name AS primary_domain
    FROM whp.ai_monitor_ignore_rules r
    LEFT JOIN whp.sites s ON r.site_id = s.id
    LEFT JOIN whp.domains d ON s.primary_domain_id = d.id
    {$whereSql}
    ORDER BY r.id DESC
    LIMIT {$per_page} OFFSET {$offset}
");
$listStmt->execute($params);
$rules = $listStmt->fetchAll(PDO::FETCH_ASSOC);

$sites = $db->query("
    SELECT s.id, s.site_name, d.domain_name AS primary_domain
    FROM whp.sites s
    LEFT JOIN whp.domains d ON s.primary_domain_id = d.id
    ORDER BY s.site_name ASC
")->fetchAll(PDO::FETCH_ASSOC);

// User- or site-scoped rules whose (category, title_substr, raw_regex) tuple
// is shared by 3+ distinct usernames are promotion candidates.
$candidatesStmt = $db->query("
    SELECT
        COALESCE(match_category, '')        AS k_category,
        COALESCE(match_title_substr, '')    AS k_title,
        COALESCE(match_raw_regex, '')       AS k_regex,
        COUNT(DISTINCT username)            AS distinct_users,
        COUNT(*)                            AS rule_count,
        GROUP_CONCAT(DISTINCT username ORDER BY username SEPARATOR ', ') AS usernames
    FROM whp.ai_monitor_ignore_rules
    WHERE scope IN ('user','site') AND enabled = 1
    GROUP BY k_category, k_title, k_regex
    HAVING distinct_users >= 3
    ORDER BY distinct_users DESC, rule_count DESC
");
$candidates = $candidatesStmt->fetchAll(PDO::FETCH_ASSOC);

$show_hits_for = isset($_GET['hits_for']) ? (int)$_GET['hits_for'] : 0;
$hits = [];
$hits_rule = null;
if ($show_hits_for) {
    $hStmt = $db->prepare("
        SELECT h.*, d.domain_name AS primary_domain
        FROM whp.ai_monitor_ignore_hits h
        LEFT JOIN whp.sites s ON h.site_id = s.id
        LEFT JOIN whp.domains d ON s.primary_domain_id = d.id
        WHERE h.rule_id = ?
        ORDER BY h.id DESC
        LIMIT 50
    ");
    $hStmt->execute([$show_hits_for]);
    $hits = $hStmt->fetchAll(PDO::FETCH_ASSOC);

    $rStmt = $db->prepare("SELECT * FROM whp.ai_monitor_ignore_rules WHERE id = ?");
    $rStmt->execute([$show_hits_for]);
    $hits_rule = $rStmt->fetch(PDO::FETCH_ASSOC);
}

$csrf = get_csrf_token();
?>

<div class="container-fluid mt-3">
    <h2 class="mb-3"><i class="fa fa-ban"></i> AI Monitor Ignore Rules</h2>
    <p class="text-muted">
        Rules in this table prevent matching findings from becoming customer-visible
        issues. Match fields combine with AND-semantics: if a rule sets multiple
        match_* columns, all of them must match the finding for the rule to apply.
    </p>

    <?php if ($message !== ''): ?>
        <div class="alert alert-<?php echo $message_type; ?>"><?php echo $message; ?></div>
    <?php endif; ?>

    <?php if ($candidates): ?>
    <div class="card mb-3 border-warning">
        <div class="card-header bg-warning-subtle">
            <i class="fa fa-arrow-up"></i> Candidate global rules
            <small class="text-muted ms-2">(shared across 3+ users - consider promoting to global)</small>
        </div>
        <div class="card-body p-0">
            <table class="table table-sm mb-0">
                <thead>
                    <tr>
                        <th>Category</th>
                        <th>Title contains</th>
                        <th>Regex</th>
                        <th>Distinct users</th>
                        <th>Rule count</th>
                        <th>Users</th>
                    </tr>
                </thead>
                <tbody>
                <?php foreach ($candidates as $c): ?>
                    <tr>
                        <td><?php echo htmlspecialchars($c['k_category']); ?></td>
                        <td><?php echo htmlspecialchars($c['k_title']); ?></td>
                        <td><code><?php echo htmlspecialchars($c['k_regex']); ?></code></td>
                        <td><?php echo (int)$c['distinct_users']; ?></td>
                        <td><?php echo (int)$c['rule_count']; ?></td>
                        <td class="small"><?php echo htmlspecialchars($c['usernames']); ?></td>
                    </tr>
                <?php endforeach; ?>
                </tbody>
            </table>
        </div>
    </div>
    <?php endif; ?>

    <div class="card mb-3">
        <div class="card-header">
            <a class="text-decoration-none" data-bs-toggle="collapse" href="#newRuleBody" role="button" aria-expanded="false">
                <i class="fa fa-plus-circle"></i> Add a new rule
            </a>
        </div>
        <div class="collapse" id="newRuleBody">
            <div class="card-body">
                <form method="post">
                    <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf); ?>">
                    <input type="hidden" name="action" value="create_rule">
                    <div class="row g-2">
                        <div class="col-md-3">
                            <label class="form-label">Scope</label>
                            <select class="form-select" name="scope" id="newScope" required>
                                <option value="global">global</option>
                                <option value="user">user</option>
                                <option value="site">site</option>
                            </select>
                        </div>
                        <div class="col-md-3" id="newUsernameWrap" style="display:none;">
                            <label class="form-label">Username</label>
                            <input type="text" class="form-control" name="username" maxlength="32">
                        </div>
                        <div class="col-md-3" id="newSiteWrap" style="display:none;">
                            <label class="form-label">Site</label>
                            <select class="form-select" name="site_id">
                                <option value="">-- select --</option>
                                <?php foreach ($sites as $s): ?>
                                    <option value="<?php echo (int)$s['id']; ?>">
                                        <?php echo htmlspecialchars($s['site_name'] . ' (' . ($s['primary_domain'] ?? '') . ')'); ?>
                                    </option>
                                <?php endforeach; ?>
                            </select>
                        </div>
                    </div>
                    <hr>
                    <p class="text-muted small mb-2">Match fields (AND-combined). At least one is required.</p>
                    <div class="row g-2">
                        <div class="col-md-3">
                            <label class="form-label">match_category</label>
                            <input type="text" class="form-control" name="match_category" maxlength="50" placeholder="e.g. php_error">
                        </div>
                        <div class="col-md-3">
                            <label class="form-label">match_severity</label>
                            <select class="form-select" name="match_severity">
                                <option value="">--</option>
                                <option value="critical">critical</option>
                                <option value="warning">warning</option>
                                <option value="info">info</option>
                            </select>
                        </div>
                        <div class="col-md-3">
                            <label class="form-label">match_title_substr</label>
                            <input type="text" class="form-control" name="match_title_substr" maxlength="255" placeholder="case-insensitive substring">
                        </div>
                        <div class="col-md-3">
                            <label class="form-label">match_raw_regex</label>
                            <input type="text" class="form-control" name="match_raw_regex" maxlength="500" placeholder="PCRE pattern (no delimiters)">
                        </div>
                    </div>
                    <div class="mt-2">
                        <label class="form-label">Reason <span class="text-danger">*</span></label>
                        <textarea class="form-control" name="reason" rows="2" required maxlength="2000"></textarea>
                    </div>
                    <button type="submit" class="btn btn-primary mt-2"><i class="fa fa-save"></i> Create rule</button>
                </form>
            </div>
        </div>
    </div>

    <form method="get" class="row g-2 align-items-end mb-2">
        <input type="hidden" name="page" value="ai-monitor-ignore-rules">
        <div class="col-md-2">
            <label class="form-label small">Filter scope</label>
            <select class="form-select form-select-sm" name="filter_scope">
                <option value="">All</option>
                <option value="global" <?php echo $filter_scope === 'global' ? 'selected' : ''; ?>>global</option>
                <option value="user"   <?php echo $filter_scope === 'user'   ? 'selected' : ''; ?>>user</option>
                <option value="site"   <?php echo $filter_scope === 'site'   ? 'selected' : ''; ?>>site</option>
            </select>
        </div>
        <div class="col-md-2">
            <label class="form-label small">Filter enabled</label>
            <select class="form-select form-select-sm" name="filter_enabled">
                <option value="">All</option>
                <option value="1" <?php echo $filter_enabled === '1' ? 'selected' : ''; ?>>Enabled</option>
                <option value="0" <?php echo $filter_enabled === '0' ? 'selected' : ''; ?>>Disabled</option>
            </select>
        </div>
        <div class="col-md-2">
            <button class="btn btn-sm btn-outline-secondary" type="submit">Apply</button>
        </div>
        <div class="col text-end small text-muted">
            <?php echo $total; ?> rule(s)
        </div>
    </form>

    <div class="card">
        <div class="card-body p-0">
            <table class="table table-sm mb-0">
                <thead>
                    <tr>
                        <th>#</th>
                        <th>Scope</th>
                        <th>Target</th>
                        <th>Match</th>
                        <th>Reason</th>
                        <th>Hits</th>
                        <th>Last hit</th>
                        <th>Created</th>
                        <th>Enabled</th>
                        <th></th>
                    </tr>
                </thead>
                <tbody>
                <?php if (!$rules): ?>
                    <tr><td colspan="10" class="text-center text-muted py-4">No rules.</td></tr>
                <?php endif; ?>
                <?php foreach ($rules as $r): ?>
                    <tr>
                        <td><?php echo (int)$r['id']; ?></td>
                        <td><span class="badge bg-secondary"><?php echo htmlspecialchars($r['scope']); ?></span></td>
                        <td class="small">
                            <?php
                            if ($r['scope'] === 'user') {
                                echo htmlspecialchars($r['username'] ?? '');
                            } elseif ($r['scope'] === 'site') {
                                echo htmlspecialchars(($r['site_name'] ?? '') . ' (' . ($r['primary_domain'] ?? '') . ')');
                            } else {
                                echo '-';
                            }
                            ?>
                        </td>
                        <td class="small">
                            <?php
                            $parts = [];
                            if ($r['match_category'] !== null && $r['match_category'] !== '') {
                                $parts[] = 'cat=' . htmlspecialchars($r['match_category']);
                            }
                            if ($r['match_severity'] !== null && $r['match_severity'] !== '') {
                                $parts[] = 'sev=' . htmlspecialchars($r['match_severity']);
                            }
                            if ($r['match_title_substr'] !== null && $r['match_title_substr'] !== '') {
                                $parts[] = 'title~"' . htmlspecialchars($r['match_title_substr']) . '"';
                            }
                            if ($r['match_raw_regex'] !== null && $r['match_raw_regex'] !== '') {
                                $parts[] = 're=' . htmlspecialchars($r['match_raw_regex']);
                            }
                            echo implode(' &amp; ', $parts);
                            ?>
                        </td>
                        <td class="small" style="max-width:240px;"><?php echo nl2br(htmlspecialchars($r['reason'])); ?></td>
                        <td>
                            <a href="?page=ai-monitor-ignore-rules&amp;hits_for=<?php echo (int)$r['id']; ?>">
                                <?php echo (int)$r['hit_count']; ?>
                            </a>
                        </td>
                        <td class="small"><?php echo htmlspecialchars($r['last_hit_at'] ?? '-'); ?></td>
                        <td class="small">
                            <?php echo htmlspecialchars($r['created_by']); ?><br>
                            <span class="text-muted"><?php echo htmlspecialchars($r['created_at']); ?></span>
                        </td>
                        <td>
                            <?php if ((int)$r['enabled'] === 1): ?>
                                <span class="badge bg-success">on</span>
                            <?php else: ?>
                                <span class="badge bg-secondary">off</span>
                            <?php endif; ?>
                        </td>
                        <td class="text-end">
                            <form method="post" class="d-inline">
                                <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf); ?>">
                                <input type="hidden" name="action" value="toggle_rule">
                                <input type="hidden" name="id" value="<?php echo (int)$r['id']; ?>">
                                <button class="btn btn-xs btn-outline-warning" title="Toggle enabled">
                                    <i class="fa fa-power-off"></i>
                                </button>
                            </form>
                            <form method="post" class="d-inline" onsubmit="return confirm('Delete this rule?');">
                                <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf); ?>">
                                <input type="hidden" name="action" value="delete_rule">
                                <input type="hidden" name="id" value="<?php echo (int)$r['id']; ?>">
                                <button class="btn btn-xs btn-outline-danger" title="Delete">
                                    <i class="fa fa-trash-o"></i>
                                </button>
                            </form>
                        </td>
                    </tr>
                <?php endforeach; ?>
                </tbody>
            </table>
        </div>
    </div>

    <?php if ($total_pages > 1): ?>
    <nav class="mt-2">
        <ul class="pagination pagination-sm">
            <?php for ($p = 1; $p <= $total_pages; $p++): ?>
                <li class="page-item <?php echo $p === $page_num ? 'active' : ''; ?>">
                    <a class="page-link" href="?page=ai-monitor-ignore-rules&amp;p=<?php echo $p; ?>&amp;filter_scope=<?php echo urlencode($filter_scope); ?>&amp;filter_enabled=<?php echo urlencode($filter_enabled); ?>">
                        <?php echo $p; ?>
                    </a>
                </li>
            <?php endfor; ?>
        </ul>
    </nav>
    <?php endif; ?>

    <?php if ($show_hits_for && $hits_rule): ?>
    <div class="card mt-4">
        <div class="card-header">
            <i class="fa fa-history"></i>
            Recent hits for rule #<?php echo (int)$hits_rule['id']; ?>
            <a href="?page=ai-monitor-ignore-rules" class="float-end small">close</a>
        </div>
        <div class="card-body p-0">
            <table class="table table-sm mb-0">
                <thead>
                    <tr>
                        <th>When</th>
                        <th>User</th>
                        <th>Site</th>
                        <th>Category</th>
                        <th>Title</th>
                        <th>Signature</th>
                    </tr>
                </thead>
                <tbody>
                <?php if (!$hits): ?>
                    <tr><td colspan="6" class="text-muted text-center py-3">No hits yet.</td></tr>
                <?php endif; ?>
                <?php foreach ($hits as $h): ?>
                    <tr>
                        <td class="small"><?php echo htmlspecialchars($h['hit_at']); ?></td>
                        <td class="small"><?php echo htmlspecialchars($h['username'] ?? '-'); ?></td>
                        <td class="small"><?php echo htmlspecialchars($h['primary_domain'] ?? ('site_id=' . (int)$h['site_id'])); ?></td>
                        <td class="small"><?php echo htmlspecialchars($h['matched_category'] ?? '-'); ?></td>
                        <td class="small"><?php echo htmlspecialchars($h['matched_title'] ?? '-'); ?></td>
                        <td class="small"><code><?php echo htmlspecialchars(substr($h['matched_signature'] ?? '', 0, 16)); ?></code></td>
                    </tr>
                <?php endforeach; ?>
                </tbody>
            </table>
        </div>
    </div>
    <?php endif; ?>
</div>

<script>
(function() {
    var scopeSel = document.getElementById('newScope');
    var userWrap = document.getElementById('newUsernameWrap');
    var siteWrap = document.getElementById('newSiteWrap');
    if (!scopeSel) return;
    function sync() {
        var v = scopeSel.value;
        userWrap.style.display = (v === 'user') ? '' : 'none';
        siteWrap.style.display = (v === 'site') ? '' : 'none';
    }
    scopeSel.addEventListener('change', sync);
    sync();
})();
</script>
