<?php
namespace Helpers\Outil;

class ArrayHelper
{

    /**
     * Similar to array_column($a, null, $path) except it
     * allow mutiple items in $a to have the same key
     * @param array<array<mixed>> $a
     * @param string|callable $path
     * @return array<array<array<mixed>>> indexed using $path
     */
    public static function indexBy(array $a, $path) :array
    {
        $m = [];
        foreach ($a as $o) {
            if (is_callable($path)) {
                $key = $path($o);
            } else {
                $key = $o[ $path ];
            }
            
            $m[$key][] = $o;
        }
        return $m;
    }

    // /**
    //  * Similar to array_column($a, null, $path) except it
    //  * allow mutiple items in $a to have the same key
    //  * @template Type of array<mixed>|object
    //  * @param array<Type> $a
    //  * @param string|callable $path
    //  * @return array<array<Type>> indexed using $path
    //  */
    // public static function indexBy(array $a, $path) :array
    // {
    //     $m = [];
    //     foreach ($a as $o) {
    //         if (is_callable($path)) {
    //             $key = $path($o);
    //         } else {
    //             $key = (is_object($o)) ? $o->{$path} : $o[ $path ];
    //         }
            
    //         $m[$key][] = $o;
    //     }
    //     return $m;
    // }

    /**
     * Similar to array_column($a, null, $path) except it
     * allow for callback
     * @template Type of mixed
     * @param array<Type> $a
     * @param callable $fn
     * @return array<Type> indexed using $path
     */
    public static function indexUniqBy(array $a, $fn) :array
    {
        $m = [];
        foreach ($a as $o) {
            $key = $fn($o);
            $m[$key] = $o;
        }
        return $m;
    }
    
    /**
     * refactorArray
     *
     * @param  array<mixed> $array
     * @return array<mixed>
     * @deprecated use php native array_values intead
     */
    public static function refactorArray(array $array) : array
    {
        $arrayTmp = [];

        foreach ($array as $val) {
            $arrayTmp[] = $val;
        }
        
        return $arrayTmp;
    }

    /**
     * @param array<mixed> $array
     * @param array<mixed>|callable $listKey
     * @return array<mixed>
     */
    public static function filterByKey(array $array, $listKey) : array
    {
        if (is_callable($listKey)) {
            $listKey = array_filter(array_keys($array), $listKey);
        }
        return array_intersect_key(
            $array,
            array_flip($listKey)
        );
    }

    /**
     * @param array<mixed> $array
     * @return mixed|null
     */
    public static function findFirst(array $array, callable $fnFilter)
    {
        foreach ($array as $item) {
            if ($fnFilter($item)) {
                return $item;
            }
        }
        return null;
    }

    /**
     * Sort an array using a given secondary array
     * @param array<mixed> $array
     * @param array<int|string> $order lsit of field in the desired order
     * @return array<mixed>
     */
    public static function sortKeyByArray(array $array, array $order)
    {
        $res = [];
        foreach ($order as $key) {
            if (! array_key_exists($key, $array)) {
                continue;
            }
            $res[ $key ] = $array[ $key ];
        }
        return $res;
    }
}
