<?php
/**
 * File for handling grouped output of multiple transients.
 *
 * @package easy-transients-for-wordpress
 */

namespace DownloadListWithIcons\Dependencies\easyTransientsForWordPress\Views;

// prevent direct access.
defined( 'ABSPATH' ) || exit;

use DownloadListWithIcons\Dependencies\easyTransientsForWordPress\Transient;
use DownloadListWithIcons\Dependencies\easyTransientsForWordPress\Transients;

/**
 * Object for handling single output of multiple transients.
 */
class Grouped {
    /**
     * Instance of this object.
     *
     * @var ?Grouped
     */
    private static ?Grouped $instance = null;

    /**
     * Constructor for this object.
     */
    private function __construct() {}

    /**
     * Prevent cloning of this object.
     *
     * @return void
     */
    private function __clone() {}

    /**
     * Return the instance of this Singleton object.
     */
    public static function get_instance(): Grouped {
        if ( is_null( self::$instance ) ) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    /**
     * Show the transients.
     *
     * @return void
     */
    public function display(): void {
        // get list of transients of this plugin.
        $transients = Transients::get_instance()->get_transients();

        // bail if list is empty.
        if( empty( $transients ) ) {
            return;
        }

        // get the transients to show.
        $transient_list = array();
        foreach ( $transients as $transient_obj ) {
            // bail if transient is not our own one.
            if ( ! $transient_obj instanceof Transient ) {
                continue;
            }

            $transient_list[] = $transient_obj;
        }

        // sort the transients: primary by their types (error > success).
        usort( $transient_list, array( $this, 'sort_by_type' ) );

        // first loop to get prev and next values.
        $prev = array();
        $next = array();
        $last = $transient_list[array_key_first( $transient_list )]->get_name();
        $first = $transient_list[array_key_first( $transient_list )]->get_name();
        $counter = 0;
        foreach ( $transient_list as $transient_obj ) {
            // save the last entry as prev for this object.
            if( $last !== $transient_obj->get_name() ) {
                $prev[ $transient_obj->get_name() ] = $last;
            }

            // save this entry as next for the last object.
            $next[ $last ] = $transient_obj->get_name();

            // remember this entry.
            $last = $transient_obj->get_name();

            // update counter.
            $counter++;
        }

        // bail if no transients are visible.
        if( 0 === $counter ) {
            return;
        }

        $next[ $last ] = $first;
        $prev[ $first ] = $last;

        ?>
        <div id="etfw-transients-grouped" class="notice">
            <div id="etfw-transients">
                <?php

                // check for active transients and show them.
                foreach ( $transient_list as $transient_obj ) {
                    // bail if transient is not set.
                    if ( ! $transient_obj->is_set() ) {
                        continue;
                    }

                    // set prev and next (necessary for the slider).
                    $transient_obj->set_prev( $prev[ $transient_obj->get_name() ] );
                    $transient_obj->set_next( $next[ $transient_obj->get_name() ] );

                    // show this transient hint.
                    $transient_obj->display();
                }

                ?>
            </div>
        </div>
        <?php
    }

    /**
     * Return mapping of states for sorting.
     *
     * @return array<string,int>
     */
    private function type_map(): array {
        return array(
            'error' => 1,
            'success' => 2,
            'hint' => 3,
            'info' => 4
        );
    }

    /**
     * Sort the list of transients by type (first error, then success).
     *
     * @param Transient $a The first transient to compare.
     * @param Transient $b The second transient to compare.
     *
     * @return int
     */
    public function sort_by_type( Transient $a, Transient $b ): int {
        if( $a->is_prioritized() ) {
            return false;
        }
        if( $b->is_prioritized() ) {
            return true;
        }
        $state_mapping = $this->type_map();
        return $state_mapping[$a->get_type()] > $state_mapping[$b->get_type()] ? 1 : -1;
    }
}
