<?php

namespace WPSN\Modules\ActivityLog\Admin;

use WPSN\Core\Branding;
use WPSN\Core\Capabilities;
use WPSN\Core\Container;
use WPSN\Core\Settings;
use WPSN\Modules\ActivityLog\ActivityLogRepository;

defined('ABSPATH') || exit;

final class ActivityLogAdmin
{
    private const PAGE_SLUG = 'wpsn-activity-log';

    private Container $container;
    private Settings $settings;

    public function __construct(Container $container)
    {
        $this->container = $container;
        $this->settings = $container->get('settings');
    }

    public function register(): void
    {
        add_action('admin_menu', [$this, 'addMenu']);
        add_action('admin_post_wpsn_activity_log_clear', [$this, 'handleClear']);
        add_action('admin_post_wpsn_activity_log_export', [$this, 'handleExport']);
    }

    public function addMenu(): void
    {
        add_management_page(
            __('SEO Activity Log', 'wp-seo-next'),
            __('SEO Activity Log', 'wp-seo-next'),
            Capabilities::CAP_TOOLS,
            self::PAGE_SLUG,
            [$this, 'render']
        );
    }

    /**
     * @param array<string,string|int> $args
     */
    private function pageUrl(array $args = []): string
    {
        $base = admin_url('tools.php');
        $args = array_merge(['page' => self::PAGE_SLUG], $args);
        return (string) add_query_arg($args, $base);
    }

    private function redirectWithNotice(string $notice, string $type = 'success', array $args = []): void
    {
        $url = $this->pageUrl(array_merge($args, [
            'wpsn_notice' => rawurlencode($notice),
            'wpsn_notice_type' => $type,
        ]));
        wp_safe_redirect($url);
        exit;
    }

    public function handleClear(): void
    {
        if (!Capabilities::canManageTools()) {
            wp_die(esc_html__('You do not have permission to perform this action.', 'wp-seo-next'));
        }

        check_admin_referer('wpsn_activity_log_clear', 'wpsn_nonce');

        $repo = new ActivityLogRepository();
        $repo->deleteAll();

        $this->redirectWithNotice(__('Activity log cleared.', 'wp-seo-next'), 'success');
    }

    public function handleExport(): void
    {
        if (!Capabilities::canManageTools()) {
            wp_die(esc_html__('You do not have permission to perform this action.', 'wp-seo-next'));
        }

        check_admin_referer('wpsn_activity_log_export', 'wpsn_nonce');

        $action = isset($_POST['filter_action']) ? sanitize_key((string) wp_unslash($_POST['filter_action'])) : '';
        $objectType = isset($_POST['filter_object_type']) ? sanitize_key((string) wp_unslash($_POST['filter_object_type'])) : '';
        $q = isset($_POST['filter_q']) ? sanitize_text_field((string) wp_unslash($_POST['filter_q'])) : '';
        $userId = isset($_POST['filter_user_id']) ? (int) $_POST['filter_user_id'] : 0;

        $dateFrom = isset($_POST['filter_date_from']) ? sanitize_text_field((string) wp_unslash($_POST['filter_date_from'])) : '';
        $dateTo = isset($_POST['filter_date_to']) ? sanitize_text_field((string) wp_unslash($_POST['filter_date_to'])) : '';
        if ($dateFrom !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $dateFrom)) {
            $dateFrom = '';
        }
        if ($dateTo !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $dateTo)) {
            $dateTo = '';
        }

        $presetRange = isset($_POST['preset_range']) ? (int) $_POST['preset_range'] : 0;
        if (in_array($presetRange, [7, 30], true)) {
            $today = gmdate('Y-m-d');
            $from = gmdate('Y-m-d', time() - (($presetRange - 1) * DAY_IN_SECONDS));
            $dateFrom = $from;
            $dateTo = $today;
        }

        $filters = [];
        if ($action !== '') {
            $filters['action'] = $action;
        }
        if ($objectType !== '') {
            $filters['object_type'] = $objectType;
        }
        if ($q !== '') {
            $filters['q'] = $q;
        }
        if ($userId > 0) {
            $filters['user_id'] = $userId;
        }

        if ($dateFrom !== '') {
            $filters['date_from'] = $dateFrom;
        }
        if ($dateTo !== '') {
            $filters['date_to'] = $dateTo;
        }

        $repo = new ActivityLogRepository();

        // Stream CSV for large logs.
        if (function_exists('set_time_limit')) {
            // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
            @set_time_limit(0);
        }

        if (ob_get_level() > 0) {
            // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
            @ob_end_clean();
        }

        nocache_headers();
        $filename = 'wpsn-activity-log-' . gmdate('Ymd-His') . '.csv';

        header('Content-Type: text/csv; charset=utf-8');
        header('Content-Disposition: attachment; filename=' . $filename);
        header('Pragma: no-cache');
        header('Expires: 0');

        $out = fopen('php://output', 'w');
        if (!is_resource($out)) {
            wp_die(esc_html__('Unable to open export stream.', 'wp-seo-next'));
        }

        fputcsv($out, [
            'created_at',
            'user_id',
            'user_login',
            'action',
            'context',
            'object_type',
            'object_id',
            'object_key',
            'message',
            'meta',
        ]);

        $offset = 0;
        $limit = 200;
        /** @var array<int,string> $userCache */
        $userCache = [];

        while (true) {
            $rows = $repo->list($limit, $offset, $filters);
            if (empty($rows)) {
                break;
            }

            foreach ($rows as $r) {
                $uid = isset($r['user_id']) ? (int) $r['user_id'] : 0;
                $login = '';
                if ($uid > 0) {
                    if (isset($userCache[$uid])) {
                        $login = $userCache[$uid];
                    } else {
                        $u = get_user_by('id', $uid);
                        $login = ($u && $u->user_login) ? (string) $u->user_login : '';
                        $userCache[$uid] = $login;
                    }
                }

                fputcsv($out, [
                    (string) ($r['created_at'] ?? ''),
                    $uid > 0 ? (string) $uid : '',
                    $login,
                    (string) ($r['action'] ?? ''),
                    (string) ($r['context'] ?? ''),
                    (string) ($r['object_type'] ?? ''),
                    isset($r['object_id']) && (int) $r['object_id'] > 0 ? (string) ((int) $r['object_id']) : '',
                    (string) ($r['object_key'] ?? ''),
                    (string) ($r['message'] ?? ''),
                    (string) ($r['meta'] ?? ''),
                ]);
            }

            $offset += $limit;
        }

        fclose($out);
        exit;
    }

    public function render(): void
    {
        if (!Capabilities::canManageTools()) {
            wp_die(esc_html__('You do not have permission to access this page.', 'wp-seo-next'));
        }

        $repo = new ActivityLogRepository();

        $action = isset($_GET['action']) ? sanitize_key((string) wp_unslash($_GET['action'])) : '';
        $objectType = isset($_GET['object_type']) ? sanitize_key((string) wp_unslash($_GET['object_type'])) : '';
        $q = isset($_GET['q']) ? sanitize_text_field((string) wp_unslash($_GET['q'])) : '';
        $userId = isset($_GET['user_id']) ? (int) $_GET['user_id'] : 0;

        $dateFrom = isset($_GET['date_from']) ? sanitize_text_field((string) wp_unslash($_GET['date_from'])) : '';
        $dateTo = isset($_GET['date_to']) ? sanitize_text_field((string) wp_unslash($_GET['date_to'])) : '';
        if ($dateFrom !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $dateFrom)) {
            $dateFrom = '';
        }
        if ($dateTo !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $dateTo)) {
            $dateTo = '';
        }

        $paged = isset($_GET['paged']) ? max(1, (int) $_GET['paged']) : 1;
        $perPage = 50;
        $offset = ($paged - 1) * $perPage;

        $filters = [];
        if ($action !== '') {
            $filters['action'] = $action;
        }
        if ($objectType !== '') {
            $filters['object_type'] = $objectType;
        }
        if ($q !== '') {
            $filters['q'] = $q;
        }
        if ($userId > 0) {
            $filters['user_id'] = $userId;
        }
        if ($dateFrom !== '') {
            $filters['date_from'] = $dateFrom;
        }
        if ($dateTo !== '') {
            $filters['date_to'] = $dateTo;
        }

        $total = $repo->count($filters);
        $rows = $repo->list($perPage, $offset, $filters);

        $actions = $repo->distinctActions();
        $objectTypes = $repo->distinctObjectTypes();

        $notice = isset($_GET['wpsn_notice']) ? sanitize_text_field((string) wp_unslash($_GET['wpsn_notice'])) : '';
        $noticeType = isset($_GET['wpsn_notice_type']) ? sanitize_key((string) wp_unslash($_GET['wpsn_notice_type'])) : 'success';
        if (!in_array($noticeType, ['success', 'error', 'warning', 'info'], true)) {
            $noticeType = 'success';
        }

        $brand = Branding::brand($this->settings);
        if ($brand === '') {
            $brand = __('WP SEO Next', 'wp-seo-next');
        }

        echo '<div class="wrap">';
        echo '<h1>' . esc_html__('SEO Activity Log', 'wp-seo-next') . '</h1>';
        echo '<p class="description">' . esc_html__('A local log of important admin actions (redirects, bulk apply, IndexNow submits, import/export, profile rollouts). Useful for agencies and teams.', 'wp-seo-next') . '</p>';

        if ($notice !== '') {
            $class = 'notice-' . $noticeType;
            echo '<div class="notice ' . esc_attr($class) . ' is-dismissible"><p>' . esc_html($notice) . '</p></div>';
        }

        echo '<div class="notice notice-info" style="max-width: 1100px;"><p>' . sprintf(
            /* translators: %s is brand */
            esc_html__('%s records actions locally. Set retention in Settings → Privacy.', 'wp-seo-next'),
            esc_html($brand)
        ) . '</p></div>';

        $today = gmdate('Y-m-d');
        $last7 = gmdate('Y-m-d', time() - (6 * DAY_IN_SECONDS));
        $last30 = gmdate('Y-m-d', time() - (29 * DAY_IN_SECONDS));
        $baseArgs = [];
        if ($action !== '') {
            $baseArgs['action'] = $action;
        }
        if ($objectType !== '') {
            $baseArgs['object_type'] = $objectType;
        }
        if ($q !== '') {
            $baseArgs['q'] = $q;
        }
        if ($userId > 0) {
            $baseArgs['user_id'] = $userId;
        }

        // Filters.
        echo '<form method="get" style="margin: 10px 0;">';
        echo '<input type="hidden" name="page" value="' . esc_attr(self::PAGE_SLUG) . '" />';

        echo '<label style="margin-right:10px;">' . esc_html__('Action', 'wp-seo-next') . ': ';
        echo '<select name="action">';
        echo '<option value="">' . esc_html__('All', 'wp-seo-next') . '</option>';
        foreach ($actions as $a) {
            echo '<option value="' . esc_attr($a) . '" ' . selected($action, $a, false) . '>' . esc_html($a) . '</option>';
        }
        echo '</select></label>';

        echo '<label style="margin-right:10px;">' . esc_html__('Object type', 'wp-seo-next') . ': ';
        echo '<select name="object_type">';
        echo '<option value="">' . esc_html__('All', 'wp-seo-next') . '</option>';
        foreach ($objectTypes as $ot) {
            echo '<option value="' . esc_attr($ot) . '" ' . selected($objectType, $ot, false) . '>' . esc_html($ot) . '</option>';
        }
        echo '</select></label>';

        echo '<label style="margin-right:10px;">' . esc_html__('User ID', 'wp-seo-next') . ': ';
        echo '<input type="number" name="user_id" value="' . esc_attr($userId > 0 ? (string) $userId : '') . '" style="width:90px;" />';
        echo '</label>';

        echo '<label style="margin-right:10px;">' . esc_html__('Search', 'wp-seo-next') . ': ';
        echo '<input type="search" name="q" value="' . esc_attr($q) . '" style="width:240px;" />';
        echo '</label>';

        echo '<label style="margin-right:10px;">' . esc_html__('From (UTC)', 'wp-seo-next') . ': ';
        echo '<input type="date" name="date_from" value="' . esc_attr($dateFrom) . '" />';
        echo '</label>';

        echo '<label style="margin-right:10px;">' . esc_html__('To (UTC)', 'wp-seo-next') . ': ';
        echo '<input type="date" name="date_to" value="' . esc_attr($dateTo) . '" />';
        echo '</label>';

        $last7Url = $this->pageUrl(array_merge($baseArgs, [
            'date_from' => $last7,
            'date_to' => $today,
        ]));
        $last30Url = $this->pageUrl(array_merge($baseArgs, [
            'date_from' => $last30,
            'date_to' => $today,
        ]));

        echo '<span style="margin-right:10px; font-size:12px; color:#666;">';
        echo '<a href="' . esc_url($last7Url) . '">' . esc_html__('Last 7 days', 'wp-seo-next') . '</a>';
        echo ' · <a href="' . esc_url($last30Url) . '">' . esc_html__('Last 30 days', 'wp-seo-next') . '</a>';
        echo '</span>';

        submit_button(__('Filter', 'wp-seo-next'), 'secondary', '', false);
        echo '&nbsp;<a class="button" href="' . esc_url($this->pageUrl()) . '">' . esc_html__('Reset', 'wp-seo-next') . '</a>';

        echo '</form>';

        // Export CSV button (respects current filters).
        echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '" style="margin: 10px 0;">';
        echo '<input type="hidden" name="action" value="wpsn_activity_log_export" />';
        wp_nonce_field('wpsn_activity_log_export', 'wpsn_nonce');
        echo '<input type="hidden" name="filter_action" value="' . esc_attr($action) . '" />';
        echo '<input type="hidden" name="filter_object_type" value="' . esc_attr($objectType) . '" />';
        echo '<input type="hidden" name="filter_user_id" value="' . esc_attr($userId > 0 ? (string) $userId : '') . '" />';
        echo '<input type="hidden" name="filter_q" value="' . esc_attr($q) . '" />';
        echo '<input type="hidden" name="filter_date_from" value="' . esc_attr($dateFrom) . '" />';
        echo '<input type="hidden" name="filter_date_to" value="' . esc_attr($dateTo) . '" />';

        echo '<button type="submit" class="button">' . esc_html__('Export CSV', 'wp-seo-next') . '</button> ';
        echo '<button type="submit" class="button" name="preset_range" value="7">' . esc_html__('Export last 7 days', 'wp-seo-next') . '</button> ';
        echo '<button type="submit" class="button" name="preset_range" value="30">' . esc_html__('Export last 30 days', 'wp-seo-next') . '</button>';
        echo '<span style="margin-left:8px; font-size:12px; color:#666;">' . esc_html__('UTC', 'wp-seo-next') . '</span>';
        echo '</form>';

        // Clear button.
        echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '" style="margin: 10px 0;">';
        echo '<input type="hidden" name="action" value="wpsn_activity_log_clear" />';
        wp_nonce_field('wpsn_activity_log_clear', 'wpsn_nonce');
        submit_button(__('Clear log', 'wp-seo-next'), 'delete', 'submit', false);
        echo '</form>';

        // Table.
        echo '<table class="widefat striped" style="max-width: 1300px;">';
        echo '<thead><tr>';
        echo '<th style="width:160px;">' . esc_html__('Date', 'wp-seo-next') . '</th>';
        echo '<th style="width:80px;">' . esc_html__('User', 'wp-seo-next') . '</th>';
        echo '<th style="width:140px;">' . esc_html__('Action', 'wp-seo-next') . '</th>';
        echo '<th style="width:200px;">' . esc_html__('Object', 'wp-seo-next') . '</th>';
        echo '<th>' . esc_html__('Message', 'wp-seo-next') . '</th>';
        echo '</tr></thead><tbody>';

        if (empty($rows)) {
            echo '<tr><td colspan="5">' . esc_html__('No activity yet.', 'wp-seo-next') . '</td></tr>';
        } else {
            foreach ($rows as $r) {
                $date = isset($r['created_at']) ? (string) $r['created_at'] : '';
                $uid = isset($r['user_id']) ? (int) $r['user_id'] : 0;
                $act = isset($r['action']) ? (string) $r['action'] : '';
                $objType = isset($r['object_type']) ? (string) $r['object_type'] : '';
                $objId = isset($r['object_id']) ? (int) $r['object_id'] : 0;
                $objKey = isset($r['object_key']) ? (string) $r['object_key'] : '';
                $msg = isset($r['message']) ? (string) $r['message'] : '';

                $userLabel = $uid > 0 ? '#' . $uid : '—';
                if ($uid > 0) {
                    $u = get_user_by('id', $uid);
                    if ($u && $u->user_login) {
                        $userLabel = esc_html($u->user_login);
                    }
                }

                echo '<tr>';
                echo '<td>' . esc_html($date) . '</td>';
                echo '<td>' . $userLabel . '</td>';
                echo '<td><code>' . esc_html($act) . '</code></td>';
                echo '<td>' . $this->renderObjectCell($objType, $objId, $objKey) . '</td>';
                echo '<td>' . esc_html($msg) . '</td>';
                echo '</tr>';
            }
        }

        echo '</tbody></table>';

        $this->renderPagination($total, $perPage, $paged, $action, $objectType, $q, $userId, $dateFrom, $dateTo);

        echo '</div>';
    }

    private function renderObjectCell(string $type, int $id, string $key): string
    {
        $type = sanitize_key($type);
        $out = '';

        if ($type === 'post' && $id > 0) {
            $url = get_edit_post_link($id);
            $title = get_the_title($id);
            $label = '#' . $id . ' ' . ($title ? $title : '');
            if ($url) {
                $out = '<a href="' . esc_url($url) . '">' . esc_html($label) . '</a>';
            } else {
                $out = esc_html($label);
            }
        } elseif ($type === 'term' && $id > 0) {
            $term = get_term($id);
            if ($term && !is_wp_error($term)) {
                $url = get_edit_term_link($term);
                $label = '#' . $id . ' ' . ($term->name ?? '');
                if ($url) {
                    $out = '<a href="' . esc_url($url) . '">' . esc_html($label) . '</a>';
                } else {
                    $out = esc_html($label);
                }
            }
        } elseif ($type === 'redirect' && $id > 0) {
            $url = admin_url('tools.php?page=wpsn-redirects');
            $out = '<a href="' . esc_url($url) . '">' . esc_html('#' . $id) . '</a>';
        } else {
            $label = $type !== '' ? $type : '—';
            if ($id > 0) {
                $label .= ' #' . $id;
            }
            if ($key !== '') {
                $label .= ' ' . $key;
            }
            $out = esc_html($label);
        }

        return $out;
    }

    private function renderPagination(int $total, int $perPage, int $paged, string $action, string $objectType, string $q, int $userId, string $dateFrom, string $dateTo): void
    {
        if ($total <= $perPage) {
            return;
        }

        $pages = (int) ceil($total / $perPage);
        if ($pages <= 1) {
            return;
        }

        $args = [];
        if ($action !== '') {
            $args['action'] = $action;
        }
        if ($objectType !== '') {
            $args['object_type'] = $objectType;
        }
        if ($q !== '') {
            $args['q'] = $q;
        }
        if ($userId > 0) {
            $args['user_id'] = $userId;
        }
        if ($dateFrom !== '') {
            $args['date_from'] = $dateFrom;
        }
        if ($dateTo !== '') {
            $args['date_to'] = $dateTo;
        }

        echo '<div class="tablenav"><div class="tablenav-pages" style="margin: 12px 0;">';
        echo paginate_links([
            'base'      => add_query_arg(array_merge(['paged' => '%#%'], $args), $this->pageUrl()),
            'format'    => '',
            'prev_text' => __('« Prev', 'wp-seo-next'),
            'next_text' => __('Next »', 'wp-seo-next'),
            'total'     => $pages,
            'current'   => $paged,
        ]);
        echo '</div></div>';
    }
}
