<?php

use BitFire\Request;
use BitFireData\Request_Display;
use ThreadFin\FileData;

use function BitFire\general_scan;
use function BitFire\sys_info;
use function ThreadFin\dbg as dbg;
use function ThreadFin\get_hidden_file;

use const BitFire\WAF_SRC;


class BFGreeter {
     public function greet( $args, $assoc_args ) {
        \WP_CLI::success("BitFire WP-CLI commands: log");
     }
}

if (defined('WP_CLI') && WP_CLI) {
    require_once WAF_SRC . "server.php";
    require_once WAF_SRC . "api.php";

    // minimal helper, zips positional args to assoc option keys in order
    if (!function_exists('merge_wpcli_args')) {
        function merge_wpcli_args(array $args, array $assoc_args) : array {
            $keys   = array_keys($assoc_args);
            $values = array_slice($args, 0, count($keys));
            return array_combine($keys, $values) ?: $assoc_args;
        }
    }

    // levenshtein based suggestion for invalid columns
    function suggest_closest_name(string $name, array $allowed) : ?string {
        $best = null;
        $best_dist = PHP_INT_MAX;
        foreach ($allowed as $cand) {
            $d = levenshtein($name, $cand);
            if ($d < $best_dist) {
                $best = $cand;
                $best_dist = $d;
            }
        }
        // only suggest if reasonably close
        return ($best_dist <= 3) ? $best : null;
    }

    \WP_CLI::add_command('bitfire malware', function ($args, $parameters) {
        if (!isset($parameters['format'])) {
            $parameters['format'] = 'table';
            \WP_CLI::line("usage: wp bitfire malware [--format=<table|json|csv>]\n");
        }
        $format = $parameters['format'] ?? 'table';

        $request = new Request();
        $request->post['load_scan'] = 1;
        $request->post['no_update'] = 1;
        $effect = general_scan($request);
        $api = $effect->read_api();
        $data = $api['data'] ?? [];

        $encoded = base64_decode($data['data']);
        $list = json_decode($encoded, true) ?: [];
        $out = [];
        $root = realpath(\BitFire\Config::str("cms_root"))."/";
        foreach ($list as $item) {
            $out[] = [
                'file' => str_replace($root, '', $item['path']??'n/a'),
                'size' => $item['file_size']??0,
                'note' => $item['note']??'n/a',
                'content' => substr($item['content'], 0, 128) . (strlen($item['content']) > 128 ? '...' : ''),
            ];
        }


        \WP_CLI\Utils\format_items($format, $out, ['file', 'size', 'note', 'content']);
    });


    \WP_CLI::add_command('bitfire stats', function ($args, $parameters) {
        \WP_CLI::line("usage: wp bitfire stats [--format=<table|json|csv>]\n");

        $format = $parameters['format'] ?? 'table';
        $r = new Request();
        $info = sys_info($r);
        $data = $info->read_api()['data'] ?? [];
        $to_merge = [];
        foreach ($data as $k => $v) {
            $tmp = "";
            if ($k == 'admins' && is_array($v)) {
                foreach ($v as $admin) {
                    $tmp .= $admin['user_login'] . ', ';
                }
                $tmp = rtrim($tmp, ',');
            }
            else if ($k == 'cpu') {
                $tmp = round($v['percent'], 3);
            }
            else if ($k == 'op_cache') {
                $to_merge = array_merge($to_merge, $v);
            }
            else if ($k == 'op_data') {
                $to_merge = array_merge($to_merge, $v);
            }
            if (!empty($tmp)) {
                $to_merge[$k] = $tmp;
            }
        }


        $final = array_merge($data, $to_merge);
        unset($final['cache_info']);
        unset($final['op_cache']);
        unset($final['admin_name']);
        unset($final['plugins']);
        unset($final['op_data']);

        $out = [];
        foreach ($final as $k => $v) {
            $out[] = ['key' => $k, 'value' => $v];
        }

        \WP_CLI\Utils\format_items($format, $out, ['key', 'value']);
    });

    \WP_CLI::add_command('bitfire log', function ($args, $parameters) {
        //$parameters = merge_wpcli_args($args, $assoc_args);


        // usage and help
        if (empty($parameters) || isset($parameters['help']) || isset($parameters['h']) || isset($parameters['?'])) {
            \WP_CLI::line("usage: wp bitfire log  (--include OR --exclude are required)

  [--include=filter,filter]
  [--exclude=filter,filter]
  [--direction=<forward|backward>]
  [--format=<table|json|csv>]
  [--length=<rows> (32)]
  [--page=<page number> (0)]
  [--start=<strtotime> can be anything strtotime supports ('10 minutes ago', 'dec 1 2025', 10:35am, etc)]
  [--columns=<comma-separated column names> default: 'human_time,ip,browser,method,url,block_code'];

  NOTE: All Times are in UTC (Greenwich Mean Time)

All available columns:
  bot, valid, pos, fingerprint, signature, ver, ip, param, ref, url, ua, os,
  reason, browser, favicon, location, method, ctr404, rr, http_code, block_code,
  post_sz, resp_sz, time, manual_mode, uuid, classification, human_time
");
            return;
        }

        $allowed_columns = [
            'bot','valid','pos','fingerprint','signature','ver','ip','param','ref','url','ua','os',
            'reason','browser','favicon', 'location','whois','method','ctr404','rr','http_code','block_code',
            'post_sz','resp_sz','time','manual_mode','uuid','classification','human_time'
        ];

        // include / exclude parsing
        $inc = [];
        $exc = [];
        if (isset($parameters['include']) && $parameters['include'] !== '') {
            $inc = array_values(array_filter(array_map('trim', explode(',', (string)$parameters['include']))));
        }
        if (isset($parameters['exclude']) && $parameters['exclude'] !== '') {
            $exc = array_values(array_filter(array_map('trim', explode(',', (string)$parameters['exclude']))));
        }
        if (empty($inc) && empty($exc)) {
            \WP_CLI::error('must supply --include or --exclude filters');
            return;
        }

        // direction alias fix, was using == instead of =
        $direction = isset($parameters['direction']) ? strtolower((string)$parameters['direction']) : 'forward';
        if ($direction === 'backward') {
            $direction = 'reverse';
        } elseif ($direction !== 'forward' && $direction !== 'reverse') {
            \WP_CLI::warning('unknown --direction, defaulting to forward');
            $direction = 'forward';
        }

        // format
        $format = isset($parameters['format']) ? strtolower((string)$parameters['format']) : 'table';
        if (!in_array($format, ['table','json','csv'], true)) {
            \WP_CLI::warning('unsupported --format, defaulting to table');
            $format = 'table';
        }

        // pagination and start time
        $length = isset($parameters['length']) ? max(1, (int)$parameters['length']) : 32;
        $page   = isset($parameters['page']) ? max(0, (int)$parameters['page']) : 0;
        $offset = $length * $page; // previous code had operator precedence issues

        $start_time = null;
        if (isset($parameters['start']) && $parameters['start'] !== '') {
            $start_time = (string)$parameters['start'];
        } else {
            // sensible defaults
            $start_time = ($direction === 'reverse') ? 'now' : 'today 00:00';
        }

        // columns, default set
        $columns = ['human_time', 'ip', 'browser', 'method', 'url', 'block_code'];
        if (isset($parameters['columns']) && $parameters['columns'] !== '') {
            // BUGFIX: original code mistakenly parsed 'exclude' here
            $requested = array_values(array_filter(array_map('trim', explode(',', (string)$parameters['columns']))));

            $validated = [];
            foreach ($requested as $col) {
                if (in_array($col, $allowed_columns, true)) {
                    $validated[] = $col;
                    continue;
                }
                $suggest = suggest_closest_name($col, $allowed_columns);
                if ($suggest) {
                    \WP_CLI::warning("unknown column '{$col}', did you mean '{$suggest}'?");
                    $validated[] = $suggest;
                } else {
                    \WP_CLI::warning("unknown column '{$col}', skipping");
                }
            }
            if (!empty($validated)) {
                $columns = array_values(array_unique($validated));
            } else {
                \WP_CLI::warning('no valid columns requested, using defaults');
            }
        }

        // build request
        $r = new Request();
        $r->post = [
            'include'        => $inc,
            'exclude'        => $exc,
            'page_direction' => $direction,
            'batch_sz'       => $length,
            'offset'         => $offset,
            'start_time'     => $start_time,
        ];

        $effect = \BitFire\load_bot_data($r);
        $api = $effect->read_api();

        $rows = $api['data']['data'] ?? [];

        // ensure human_time is present if requested
        if (!empty($rows)) {
            foreach ($rows as &$row) {
                if (!isset($row->human_time) && isset($row->time)) {
                    $row->human_time = date('H:i:s', (int)$row->time);
                }
                $row->location = $row->loc->iso??'XX';// . '_';// . ($row->loc->city??'Unknown');
                $row->location .= ', ' . $row->loc->city??'XX';
            }
            unset($row);
        }

        \WP_CLI\Utils\format_items($format, $rows, $columns);
    });
}