<?php

declare(strict_types=1);

namespace ACP\Asset\Script;

use AC\Asset\Location\Absolute;
use AC\Asset\Script;
use AC\Asset\Script\Localize\Translation;
use AC\Capabilities;
use AC\ColumnIterator;
use AC\ColumnNamesTrait;
use AC\ColumnSize;
use AC\ListScreen;
use AC\ListScreenCollection;
use AC\ListScreenRepository\Sort;
use AC\ListScreenRepository\Storage;
use AC\Settings\GeneralOption;
use AC\TableScreen;
use AC\Type\ColumnWidth;
use AC\Type\ListScreenStatus;
use AC\Type\Uri;
use ACP\Search\DefaultSegmentTrait;
use ACP\Settings\ListScreen\TableElement;
use ACP\Settings\Option\LayoutStyle;
use WP_User;

class Table extends Script
{

    use DefaultSegmentTrait;
    use ColumnNamesTrait;

    private ListScreen $list_screen;

    private ColumnSize\UserStorage $user_storage;

    private ColumnSize\ListStorage $list_storage;

    private Storage $storage;

    private GeneralOption $option_storage;

    public function __construct(
        Absolute $location,
        ListScreen $list_screen,
        ColumnSize\UserStorage $user_storage,
        ColumnSize\ListStorage $list_storage,
        Storage $storage,
        GeneralOption $option_storage
    ) {
        parent::__construct('acp-table', $location, [Script\GlobalTranslationFactory::HANDLE, 'jquery-ui-sortable']);

        $this->list_screen = $list_screen;
        $this->user_storage = $user_storage;
        $this->list_storage = $list_storage;
        $this->storage = $storage;
        $this->option_storage = $option_storage;
    }

    public function register(): void
    {
        parent::register();

        $user = wp_get_current_user();

        if ( ! $user) {
            return;
        }

        $translation = Translation::create([
            'column_sets'          => [
                'not_shown'   => __('Not shown in menu', 'codepress-admin-columns'),
                'more'        => _x('%s more', 'number of items', 'codepress-admin-columns'),
                'switch_view' => __('Switch View', 'codepress-admin-columns'),
            ],
            'column_screen_option' => [
                'button_reset'              => _x('Reset', 'column-resize-button', 'codepress-admin-columns'),
                'label'                     => __('Columns', 'codepress-admin-columns'),
                'resize_columns_tool'       => __('Resize Columns', 'codepress-admin-columns'),
                'reset_confirmation'        => sprintf(
                    '%s %s',
                    __('Restore the current column widths and order to their defaults.', 'codepress-admin-columns'),
                    __('Are you sure?', 'codepress-admin-columns')
                ),
                'save_changes'              => __('Save changes', 'codepress-admin-columns'),
                'save_changes_confirmation' => sprintf(
                    '%s %s',
                    __(
                        'Save the current column widths and order changes as the new default for ALL users.',
                        'codepress-admin-columns'
                    ),
                    __('Are you sure?', 'codepress-admin-columns')
                ),
                'tip_reset'                 => __(
                    'Reset columns to their default widths and order.',
                    'codepress-admin-columns'
                ),
                'tip_save_changes'          => __(
                    'Save the current column widths and order changes.',
                    'codepress-admin-columns'
                ),
            ],
        ]);

        $columns = $this->list_screen->get_columns();

        $this
            ->add_inline_variable('acp_table', [
                'column_sets'          => $this->get_table_views($user),
                'column_sets_style'    => $this->get_column_set_style(),
                'column_screen_option' => [
                    'has_manage_admin_cap' => current_user_can(Capabilities::MANAGE),
                ],
                'column_order'         => [
                    'active'        => $this->is_column_order_active(),
                    'current_order' => $this->get_column_names_from_collection($columns),
                ],
                'column_width'         => [
                    'active'                    => $this->is_column_resize_active(),
                    'can_reset'                 => $this->user_storage->exists($this->list_screen->get_id()),
                    'minimal_pixel_width'       => 50,
                    'column_sizes_current_user' => $this->get_column_sizes_by_user($this->list_screen),
                    'column_sizes'              => $this->get_column_sizes($columns),
                ],
            ])->localize('acp_table_i18n', $translation);
    }

    private function is_table_views_active(): bool
    {
        return (bool)apply_filters('acp/table/views/active', true);
    }

    private function get_table_views(WP_User $user): array
    {
        if ( ! $this->is_table_views_active()) {
            return [];
        }

        return array_values(
            array_map(
                [$this, 'create_column_set_vars'],
                $this->get_list_screens($user)->get_copy()
            )
        );
    }

    private function get_list_screens(WP_User $user): ListScreenCollection
    {
        $table_id = $this->list_screen->get_table_id();

        $list_screens = $this->storage->find_all_by_assigned_user(
            $table_id,
            $user,
            new Sort\UserOrder($user, $table_id),
            ListScreenStatus::create_active()
        );

        // An administrator should always be able to view the requested list screen
        if (user_can($user, Capabilities::MANAGE) && ! $list_screens->contains($this->list_screen)) {
            $list_screens->add($this->list_screen);
        }

        return $list_screens;
    }

    private function get_column_set_style(): string
    {
        return (new LayoutStyle($this->option_storage))->get_style();
    }

    private function is_column_order_active(): bool
    {
        $table_element = new TableElement\ColumnOrder();

        return (bool)apply_filters(
            'acp/column_order/active',
            $table_element->is_enabled($this->list_screen),
            $this->list_screen
        );
    }

    private function is_column_resize_active(): bool
    {
        $table_element = new TableElement\ColumnResize();

        return (bool)apply_filters(
            'ac/resize_columns/active',
            $table_element->is_enabled($this->list_screen),
            $this->list_screen
        );
    }

    private function get_column_sizes_by_user(ListScreen $list_screen): array
    {
        $result = [];

        foreach ($this->user_storage->get_all($list_screen->get_id()) as $column_name => $width) {
            $result[$column_name] = $this->create_vars($width);
        }

        return $result;
    }

    private function create_vars(ColumnWidth $width): array
    {
        return [
            'value' => $width->get_value(),
            'unit'  => $width->get_unit(),
        ];
    }

    private function get_column_sizes(ColumnIterator $columns): array
    {
        $result = [];

        foreach ($this->list_storage->get_all($columns) as $column_name => $width) {
            $result[$column_name] = $this->create_vars($width);
        }

        return $result;
    }

    private function create_column_set_vars(ListScreen $list_screen): array
    {
        $column_set = [
            'id'                 => (string)$list_screen->get_id(),
            'label'              => $list_screen->get_title()
                ? htmlspecialchars_decode($list_screen->get_title())
                : $list_screen->get_label(),
            'url'                => (string)$this->add_filter_args_to_url($list_screen->get_table_url(), $list_screen),
            'pre_filtered'       => false,
            'pre_filtered_label' => null,
        ];

        $default_segment = $this->get_default_segment($list_screen);

        if ($default_segment) {
            $column_set['pre_filtered_label'] = sprintf(
                __('Filtered by: %s', 'codepress-admin-columns'),
                $default_segment->get_name()
            );
        }

        return $column_set;
    }

    private function add_filter_args_to_url(Uri $url, ListScreen $list_screen): Uri
    {
        $args = [
            'post_status',
            'author',
        ];

        $table_screen = $list_screen->get_table_screen();

        switch (true) {
            case $table_screen instanceof TableScreen\User :
                $args[] = 'role';
                break;
            case $table_screen instanceof TableScreen\Comment :
                $args[] = 'comment_status';
                break;
        }

        $args = (array)apply_filters(
            'ac/table/query_args_whitelist',
            $args,
            $list_screen
        );

        foreach ($args as $arg) {
            $value = filter_input(INPUT_GET, $arg, FILTER_SANITIZE_FULL_SPECIAL_CHARS);

            if ($value) {
                $url = $url->with_arg($arg, $value);
            }
        }

        return $url;
    }

}