<?php

namespace GriffinForms\Admin\Html\Pages\Settings;

use GriffinForms\Includes\Security\Capabilities;
use GriffinForms\Includes\Api\WebhookDelivery;

class CapabilityMatrix extends \GriffinForms\Admin\Html\Pages\Settings\Format
{
    private const DEVICE_OPTION_PREFIX = 'api_device_registry_user_';

    protected array $role_matrix = [];
    protected array $user_overrides = [];

    protected function setRoleMatrix(): void
    {
        $stored = $this->settings->getOption(Capabilities::OPTION_API_ROLE_CAPABILITY_MAP, Capabilities::roleDefaultMatrix());
        $this->role_matrix = Capabilities::normalizeRoleMatrix($stored);
    }

    protected function setUserOverrides(): void
    {
        $stored = $this->settings->getOption(Capabilities::OPTION_API_USER_CAPABILITY_OVERRIDES, []);
        $this->user_overrides = Capabilities::normalizeUserOverrides($stored);
    }

    protected function settingsGroupOptions()
    {
        echo '<tr><th scope="row">' . esc_html($this->lang->getText('role_assignment_section_title')) . '</th><td>';
        echo '<p class="description">' . esc_html($this->lang->getText('role_assignment_section_description')) . '</p>';
        echo '</td></tr>';

        $this->getOptionHtml('api_feature_enabled');
        $this->getOptionHtml('api_kill_switch');
        $this->getOptionHtml('api_webhook_submission_created_enabled');
        $this->getOptionHtml('api_webhook_submission_created_url');
        $this->getOptionHtml('api_webhook_submission_created_secret');
        $this->getOptionHtml('api_webhook_submission_created_timeout');
        $this->renderDeviceRegistryAdminRow();
        $this->getOptionHtml('api_role_capability_map');
        $this->getOptionHtml('api_user_capability_overrides');
    }

    protected function getApiFeatureEnabledHtml($input_id)
    {
        $value = (int) $this->settings->getOption(Capabilities::OPTION_API_FEATURE_ENABLED, 1);
        echo '<label for="' . esc_attr($input_id) . '">';
        echo '<input type="checkbox" id="' . esc_attr($input_id) . '" name="api_feature_enabled" value="1" ' . checked(1, $value, false) . ' /> ';
        echo esc_html($this->lang->getText('api_feature_enabled', 'label'));
        echo '</label>';
        $this->getOptionDescription('api_feature_enabled');
    }

    protected function getApiKillSwitchHtml($input_id)
    {
        $value = (int) $this->settings->getOption(Capabilities::OPTION_API_KILL_SWITCH, 0);
        echo '<label for="' . esc_attr($input_id) . '">';
        echo '<input type="checkbox" id="' . esc_attr($input_id) . '" name="api_kill_switch" value="1" ' . checked(1, $value, false) . ' /> ';
        echo esc_html($this->lang->getText('api_kill_switch', 'label'));
        echo '</label>';
        $this->getOptionDescription('api_kill_switch');
    }

    protected function getApiWebhookSubmissionCreatedEnabledHtml($input_id)
    {
        $value = (int) $this->settings->getOption(WebhookDelivery::OPTION_WEBHOOK_ENABLED, 0);
        echo '<label for="' . esc_attr($input_id) . '">';
        echo '<input type="checkbox" id="' . esc_attr($input_id) . '" name="api_webhook_submission_created_enabled" value="1" ' . checked(1, $value, false) . ' /> ';
        echo esc_html($this->lang->getText('api_webhook_submission_created_enabled', 'label'));
        echo '</label>';
        $this->getOptionDescription('api_webhook_submission_created_enabled');
    }

    protected function getApiWebhookSubmissionCreatedUrlHtml($input_id)
    {
        $value = (string) $this->settings->getOption(WebhookDelivery::OPTION_WEBHOOK_URL, '');
        echo '<input type="url" id="' . esc_attr($input_id) . '" name="api_webhook_submission_created_url" class="regular-text code" value="' . esc_attr($value) . '" placeholder="https://example.com/webhooks/griffinforms" />';
        $this->getOptionDescription('api_webhook_submission_created_url');
    }

    protected function getApiWebhookSubmissionCreatedSecretHtml($input_id)
    {
        $value = (string) $this->settings->getOption(WebhookDelivery::OPTION_WEBHOOK_SECRET, '');
        echo '<input type="password" id="' . esc_attr($input_id) . '" name="api_webhook_submission_created_secret" class="regular-text code" value="' . esc_attr($value) . '" autocomplete="off" spellcheck="false" />';
        $this->getOptionDescription('api_webhook_submission_created_secret');
    }

    protected function getApiWebhookSubmissionCreatedTimeoutHtml($input_id)
    {
        $value = (int) $this->settings->getOption(WebhookDelivery::OPTION_WEBHOOK_TIMEOUT, 10);
        if ($value <= 0) {
            $value = 10;
        }
        echo '<input type="number" id="' . esc_attr($input_id) . '" name="api_webhook_submission_created_timeout" class="small-text" min="3" max="30" step="1" value="' . esc_attr((string) $value) . '" />';
        $this->getOptionDescription('api_webhook_submission_created_timeout');
    }

    protected function getApiRoleCapabilityMapHtml($input_id)
    {
        $roles = function_exists('wp_roles') ? wp_roles() : null;
        $role_names = is_object($roles) ? $roles->get_names() : [];

        $submission_caps = [
            Capabilities::CAP_VIEW_SUBMISSIONS => __('View', 'griffinforms-form-builder'),
            Capabilities::CAP_VIEW_SUBMISSION_DETAIL => __('View detail', 'griffinforms-form-builder'),
            Capabilities::CAP_EXPORT_SUBMISSION_PDF => __('Export PDF', 'griffinforms-form-builder'),
            Capabilities::CAP_SHARE_SUBMISSION_LINK => __('Share link', 'griffinforms-form-builder'),
            Capabilities::CAP_DELETE_SUBMISSION => __('Delete', 'griffinforms-form-builder'),
            Capabilities::CAP_BULK_DELETE_SUBMISSIONS => __('Bulk delete', 'griffinforms-form-builder'),
            Capabilities::CAP_MANAGE_SUBMISSION_READ_STATE => __('Manage read state', 'griffinforms-form-builder'),
        ];

        $folder_caps = [
            Capabilities::CAP_CREATE_FOLDER => __('Create', 'griffinforms-form-builder'),
            Capabilities::CAP_RENAME_FOLDER => __('Rename', 'griffinforms-form-builder'),
        ];

        $form_caps = [
            Capabilities::CAP_MOVE_FORM_FOLDER => __('Move to folder', 'griffinforms-form-builder'),
            Capabilities::CAP_RENAME_FORM => __('Rename', 'griffinforms-form-builder'),
        ];

        $device_caps = [
            Capabilities::CAP_VIEW_DEVICES => __('View', 'griffinforms-form-builder'),
            Capabilities::CAP_MANAGE_DEVICES => __('Manage', 'griffinforms-form-builder'),
        ];

        echo '<div id="' . esc_attr($input_id) . '" class="gf-capability-matrix-wrap">';
        $this->renderCapabilityTable(
            __('Submissions Capabilities', 'griffinforms-form-builder'),
            $submission_caps,
            $role_names
        );
        $this->renderCapabilityTable(
            __('Folders Capabilities', 'griffinforms-form-builder'),
            $folder_caps,
            $role_names
        );
        $this->renderCapabilityTable(
            __('Forms Capabilities', 'griffinforms-form-builder'),
            $form_caps,
            $role_names
        );
        $this->renderCapabilityTable(
            __('Devices Capabilities', 'griffinforms-form-builder'),
            $device_caps,
            $role_names
        );
        echo '</div>';
        $this->getOptionDescription('api_role_capability_map');
        echo '<p><em>' . esc_html($this->lang->getText('role_assignment_saved_note')) . '</em></p>';
    }

    protected function renderCapabilityTable(string $section_title, array $cap_labels, array $role_names): void
    {
        if (empty($cap_labels)) {
            return;
        }

        echo '<h3>' . esc_html($section_title) . '</h3>';
        echo '<table class="widefat striped" role="presentation" style="margin-bottom:16px;">';
        echo '<thead><tr><th style="padding-left: 12px;">' . esc_html__('Role', 'griffinforms-form-builder') . '</th>';
        foreach ($cap_labels as $label) {
            echo '<th><small>' . esc_html($label) . '</small></th>';
        }
        echo '</tr></thead><tbody>';

        foreach ($role_names as $role_slug => $role_label) {
            echo '<tr>';
            echo '<td style="padding-left: 12px;"><strong title="' . esc_attr((string) $role_slug) . '">' . esc_html($role_label) . '</strong></td>';
            foreach (array_keys($cap_labels) as $cap) {
                $checked = !empty($this->role_matrix[$role_slug][$cap]);
                $field_id = 'gf-capability-matrix-' . esc_attr($role_slug) . '-' . esc_attr(md5($cap));
                echo '<td>';
                echo '<label for="' . esc_attr($field_id) . '" class="screen-reader-text">' . esc_html($role_label . ' ' . $cap) . '</label>';
                echo '<input type="checkbox" id="' . esc_attr($field_id) . '" data-gf-role-cap="1" data-role="' . esc_attr((string) $role_slug) . '" data-cap="' . esc_attr($cap) . '" ' . checked(true, $checked, false) . ' />';
                echo '</td>';
            }
            echo '</tr>';
        }

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

    protected function getApiUserCapabilityOverridesHtml($input_id)
    {
        $json = empty($this->user_overrides)
            ? '{}'
            : wp_json_encode($this->user_overrides, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
        echo '<textarea id="' . esc_attr($input_id) . '" name="api_user_capability_overrides" class="large-text code" rows="8" spellcheck="false">' . esc_textarea((string) $json) . '</textarea>';
        $this->getOptionDescription('api_user_capability_overrides');
    }

    protected function renderDeviceRegistryAdminRow(): void
    {
        $rows = $this->getDeviceRegistryRows();
        $nonce = wp_create_nonce('griffinforms_device_registry_admin');

        echo '<tr>';
        echo '<th scope="row">' . esc_html__('Authorized Devices', 'griffinforms-form-builder') . '</th>';
        echo '<td>';
        echo '<input type="hidden" id="gf-device-registry-admin-nonce" value="' . esc_attr($nonce) . '" />';
        echo '<p class="description">' . esc_html__('Shows currently authorized companion devices. Remove one or more devices per user.', 'griffinforms-form-builder') . '</p>';

        if (empty($rows)) {
            echo '<p><em>' . esc_html__('No registered devices found.', 'griffinforms-form-builder') . '</em></p>';
            echo '</td></tr>';
            return;
        }

        foreach ($rows as $entry) {
            $user_id = (int) ($entry['user_id'] ?? 0);
            $user_title = (string) ($entry['user_title'] ?? ('User #' . $user_id));
            $user_subtitle = (string) ($entry['user_subtitle'] ?? '');
            $active_count = (int) ($entry['active_count'] ?? 0);
            $total_count = (int) ($entry['total_count'] ?? 0);
            $devices = is_array($entry['devices'] ?? null) ? $entry['devices'] : [];

            echo '<div class="gf-device-admin-group" style="margin-top:12px; padding:12px; border:1px solid #e5e7eb; border-radius:6px;">';
            echo '<div style="display:flex; align-items:center; justify-content:space-between; gap:10px;">';
            echo '<div class="gf-device-user-head">';
            echo '<strong class="gf-device-user-title">' . esc_html($user_title) . '</strong>';
            if ($user_subtitle !== '') {
                echo '<div class="gf-device-user-subtitle">' . esc_html($user_subtitle) . '</div>';
            }
            echo '</div>';
            echo '<div style="display:flex; gap:8px;">';
            echo '<button type="button" class="button button-secondary gf-device-remove-selected-btn" data-user-id="' . esc_attr((string) $user_id) . '">' . esc_html__('Remove selected', 'griffinforms-form-builder') . '</button>';
            echo '<button type="button" class="button button-secondary gf-device-remove-all-btn" data-user-id="' . esc_attr((string) $user_id) . '">' . esc_html__('Remove all', 'griffinforms-form-builder') . '</button>';
            echo '</div>';
            echo '</div>';
            echo '<p class="description" style="margin-top:4px;">' . esc_html(sprintf(__('Authorized: %1$d, Total stored: %2$d', 'griffinforms-form-builder'), $active_count, $total_count)) . '</p>';

            $table_wrap_style = 'margin-top:8px;';
            if ($active_count > 10) {
                $table_wrap_style .= 'max-height:460px;overflow-y:auto;overflow-x:auto;border:1px solid #e5e7eb;border-radius:4px;';
            }
            echo '<div class="gf-device-admin-table-wrap" style="' . esc_attr($table_wrap_style) . '">';
            echo '<table class="widefat striped gf-device-admin-table" role="presentation" style="margin-top:0;">';
            echo '<colgroup>';
            echo '<col style="width:38px;" />';
            echo '<col style="width:36%;" />';
            echo '<col style="width:14%;" />';
            echo '<col style="width:14%;" />';
            echo '<col style="width:22%;" />';
            echo '<col style="width:120px;" />';
            echo '</colgroup>';
            echo '<thead><tr>';
            echo '<th style="width:38px;position:sticky;top:0;background:#f6f7f7;z-index:1;"><input type="checkbox" class="gf-device-select-all" data-user-id="' . esc_attr((string) $user_id) . '" /></th>';
            echo '<th style="position:sticky;top:0;background:#f6f7f7;z-index:1;">' . esc_html__('Device ID', 'griffinforms-form-builder') . '</th>';
            echo '<th style="position:sticky;top:0;background:#f6f7f7;z-index:1;">' . esc_html__('Platform', 'griffinforms-form-builder') . '</th>';
            echo '<th style="position:sticky;top:0;background:#f6f7f7;z-index:1;">' . esc_html__('State', 'griffinforms-form-builder') . '</th>';
            echo '<th style="position:sticky;top:0;background:#f6f7f7;z-index:1;">' . esc_html__('Added', 'griffinforms-form-builder') . '</th>';
            echo '<th style="position:sticky;top:0;background:#f6f7f7;z-index:1;">' . esc_html__('Action', 'griffinforms-form-builder') . '</th>';
            echo '</tr></thead><tbody>';

            foreach ($devices as $device) {
                $device_id = sanitize_text_field((string) ($device['device_id'] ?? ''));
                if ($device_id === '') {
                    continue;
                }
                $is_active = empty($device['deleted_at']);
                if (!$is_active) {
                    continue;
                }
                $platform = sanitize_text_field((string) ($device['platform'] ?? 'unknown'));
                $platform_icon_url = $this->getDevicePlatformIconUrl($platform);
                $token_state = sanitize_text_field((string) ($device['token_state'] ?? 'unknown'));
                $state_meta = $this->formatDeviceStateMeta($token_state, $is_active);
                $state_label = (string) ($state_meta['label'] ?? __('Unknown', 'griffinforms-form-builder'));
                $state_slug = (string) ($state_meta['slug'] ?? 'unknown');
                $updated_at_raw = sanitize_text_field((string) ($device['updated_at'] ?? ''));
                $updated_at = $this->formatDeviceUpdatedAt($updated_at_raw);

                echo '<tr>';
                echo '<td><input type="checkbox" class="gf-device-select" data-user-id="' . esc_attr((string) $user_id) . '" data-device-id="' . esc_attr($device_id) . '" /></td>';
                echo '<td title="' . esc_attr($device_id) . '"><code class="gf-device-id-code">' . esc_html($device_id) . '</code></td>';
                echo '<td>';
                echo '<span class="gf-device-platform">';
                echo '<img class="gf-device-platform-icon" src="' . esc_url($platform_icon_url) . '" alt="" aria-hidden="true" loading="lazy" decoding="async" />';
                echo '<span class="gf-device-platform-label">' . esc_html($platform) . '</span>';
                echo '</span>';
                echo '</td>';
                echo '<td><span class="gf-device-state-badge gf-device-state-' . esc_attr($state_slug) . '">' . esc_html($state_label) . '</span></td>';
                echo '<td title="' . esc_attr($updated_at_raw) . '">' . esc_html($updated_at) . '</td>';
                echo '<td><button type="button" class="button button-small gf-device-remove-btn" data-user-id="' . esc_attr((string) $user_id) . '" data-device-id="' . esc_attr($device_id) . '">' . esc_html__('Remove', 'griffinforms-form-builder') . '</button></td>';
                echo '</tr>';
            }

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

        echo '</td>';
        echo '</tr>';
    }

    protected function getDeviceRegistryRows(): array
    {
        global $wpdb;

        $table = $this->config->getTable('options');
        $rows = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT option_name FROM %i WHERE option_name LIKE %s ORDER BY option_name ASC",
                $table,
                self::DEVICE_OPTION_PREFIX . '%'
            ),
            ARRAY_A
        );

        $result = [];
        foreach ((array) $rows as $row) {
            $option_name = (string) ($row['option_name'] ?? '');
            if ($option_name === '' || strpos($option_name, self::DEVICE_OPTION_PREFIX) !== 0) {
                continue;
            }

            $user_id = absint(substr($option_name, strlen(self::DEVICE_OPTION_PREFIX)));
            if ($user_id <= 0) {
                continue;
            }

            $registry = $this->settings->getOption($option_name, []);
            if (!is_array($registry) || empty($registry)) {
                continue;
            }

            $devices = [];
            $active_devices = [];
            $active_count = 0;
            foreach ($registry as $device) {
                if (!is_array($device) || empty($device['device_id'])) {
                    continue;
                }
                $devices[] = $device;
                if (empty($device['deleted_at'])) {
                    $active_count++;
                    $active_devices[] = $device;
                }
            }
            if (empty($active_devices)) {
                continue;
            }

            usort($active_devices, static function ($a, $b) {
                $a_updated = strtotime((string) ($a['updated_at'] ?? '1970-01-01 00:00:00')) ?: 0;
                $b_updated = strtotime((string) ($b['updated_at'] ?? '1970-01-01 00:00:00')) ?: 0;
                return $b_updated <=> $a_updated;
            });

            $user = get_user_by('id', $user_id);
            $name_data = $this->buildDeviceUserIdentity($user, $user_id);

            $result[] = [
                'user_id' => $user_id,
                'user_title' => $name_data['title'],
                'user_subtitle' => $name_data['subtitle'],
                'active_count' => $active_count,
                'total_count' => count($devices),
                'devices' => $active_devices,
            ];
        }

        return $result;
    }

    private function buildDeviceUserIdentity($user, int $user_id): array
    {
        if (!is_object($user)) {
            return [
                'title' => sprintf(__('User #%d', 'griffinforms-form-builder'), $user_id),
                'subtitle' => '',
            ];
        }

        $first_name = trim((string) get_user_meta($user_id, 'first_name', true));
        $last_name = trim((string) get_user_meta($user_id, 'last_name', true));
        $full_name = trim($first_name . ' ' . $last_name);
        $display_name = trim((string) ($user->display_name ?? ''));
        $user_login = trim((string) ($user->user_login ?? ''));

        $title = $full_name !== '' ? $full_name : ($display_name !== '' ? $display_name : sprintf(__('User #%d', 'griffinforms-form-builder'), $user_id));
        $subtitle_parts = [];
        if ($user_login !== '') {
            $subtitle_parts[] = '@' . $user_login;
        }
        $subtitle_parts[] = sprintf(__('User ID: %d', 'griffinforms-form-builder'), $user_id);

        return [
            'title' => $title,
            'subtitle' => implode(' • ', $subtitle_parts),
        ];
    }

    private function getDevicePlatformIconUrl(string $platform): string
    {
        $platform_key = $this->normalizeDevicePlatformKey($platform);
        $filename = $platform_key . '.svg';
        $root_path = trailingslashit($this->config->getRootPath());
        $root_url = trailingslashit($this->config->getRootUrl());
        $icon_path = $root_path . 'admin/images/device-icons/' . $filename;
        if (is_string($icon_path) && file_exists($icon_path)) {
            return $root_url . 'admin/images/device-icons/' . rawurlencode($filename);
        }

        return $root_url . 'admin/images/device-icons/unknown.svg';
    }

    private function normalizeDevicePlatformKey(string $platform): string
    {
        $key = strtolower(trim($platform));
        if ($key === 'iphone' || $key === 'ipad' || $key === 'ipados') {
            return 'ios';
        }
        if ($key === 'mac' || $key === 'macosx' || $key === 'osx' || $key === 'darwin') {
            return 'macos';
        }
        if ($key === 'win' || $key === 'windows_nt') {
            return 'windows';
        }
        if ($key === '') {
            return 'unknown';
        }

        $allowed = ['macos', 'ios', 'android', 'windows', 'linux', 'unknown'];
        return in_array($key, $allowed, true) ? $key : 'unknown';
    }

    private function formatDeviceUpdatedAt(string $raw): string
    {
        $raw = trim($raw);
        if ($raw === '') {
            return '—';
        }

        $format = trim((string) get_option('date_format') . ' ' . (string) get_option('time_format'));
        if ($format === '') {
            $format = 'Y-m-d H:i:s';
        }

        // Stored DB timestamps are UTC (`Y-m-d H:i:s`) in this surface.
        if (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', $raw) === 1) {
            $localized = get_date_from_gmt($raw, $format);
            if (is_string($localized) && $localized !== '') {
                return $localized;
            }
        }

        $dt = date_create_immutable($raw);
        if ($dt === false) {
            return $raw;
        }

        $tz = wp_timezone();
        $localized_dt = $dt->setTimezone($tz);
        return wp_date($format, $localized_dt->getTimestamp(), $tz);
    }

    private function formatDeviceStateMeta(string $token_state, bool $is_active): array
    {
        if (!$is_active) {
            return [
                'label' => __('Inactive', 'griffinforms-form-builder'),
                'slug' => 'inactive',
            ];
        }

        $state = strtolower(trim($token_state));
        if ($state === '' || $state === 'active') {
            return [
                'label' => __('Active', 'griffinforms-form-builder'),
                'slug' => 'active',
            ];
        }
        if ($state === 'unregistered') {
            return [
                'label' => __('Unregistered', 'griffinforms-form-builder'),
                'slug' => 'unregistered',
            ];
        }
        if ($state === 'invalid') {
            return [
                'label' => __('Invalid', 'griffinforms-form-builder'),
                'slug' => 'invalid',
            ];
        }

        return [
            'label' => ucwords(str_replace(['_', '-'], ' ', $state)),
            'slug' => 'unknown',
        ];
    }
}
