<?php

declare(strict_types=1);

namespace apexl\Io\modules\tabulator\Traits;

use apexl\Io\includes\RouteManager;
use apexl\Io\includes\System;
use apexl\Io\modules\tabulator\Etl\Loader\ArrayLoader;
use apexl\Io\modules\tabulator\Factories\TabulatableFactory;
use apexl\Io\modules\tabulator\Tabulatable\Tabulatable;
use apexl\Utils\Strings\Camel;
use apexl\Utils\Strings\Pluralizer;
use Arrayy\Type\StringCollection;
use DI\DependencyException;
use DI\NotFoundException;
use ReflectionClass;
use Wizaplace\Etl\Etl;
use Wizaplace\Etl\Extractors\Collection;
use function apexl\Io\container;

trait HasTabulatorView
{
    public static function tabulatorListTitle(): string
    {
        return Pluralizer::plural(static::shortName());
    }

    public static function shortName(): string
    {
        return new ReflectionClass(static::class)->getShortName();
    }

    public static function tabulatorRoute(RouteManager $routeManager): string
    {
        return $routeManager->getRoutePattern(self::tabulatorRouteName());
    }

    public static function tabulatorRouteName(): string
    {
        return sprintf('tabulator.%s', strtolower(static::shortName()));
    }

    public static function tabulatorAjaxRoute(RouteManager $routeManager): string
    {
        return $routeManager->getRoutePattern(self::tabulatorAjaxRouteName());
    }

    public static function tabulatorAjaxRouteName(): string
    {
        return sprintf('tabulator.ajax.%s', strtolower(self::shortName()));
    }

    abstract public function getNiceName(): string;

    /**
     * @throws DependencyException
     * @throws NotFoundException
     */
    public function tabulatable(): Tabulatable
    {
        return $this->tabulatableFactory()->make($this::class);
    }

    /**
     * @throws DependencyException
     * @throws NotFoundException
     */
    protected function tabulatableFactory(): TabulatableFactory
    {
        return container()->get(TabulatableFactory::class);
    }

    /**
     * @throws NotFoundException
     * @throws DependencyException
     */
    public function tabulate(array|StringCollection $fields = [], bool $excludeAjax = true): array
    {
        if (!$fields instanceof StringCollection) {
            $fields = StringCollection::createFromArray($fields);
        }

        $transformer = $this->tabulatableFactory()->make($this, $fields, $excludeAjax);

        $fields = array_filter(
            $transformer->fields($excludeAjax)->toArray(),
            fn(string $field): bool => $fields->isEmpty() || $fields->contains($field)
        );

        $tabulated = array_combine(
            $fields,
            array_map(function (string $field) {
                $value = $this->{$field};

                return is_string($value) ? trim($value) : $value;
            }, $fields)
        );

        $loader = container()->make(ArrayLoader::class);

        System::makeRegisteredService(Etl::class)
            ->extract(System::makeRegisteredService(Collection::class), [$tabulated])
            ->transform($transformer)
            ->load($loader, '')
            ->run();

        return $loader->getData()[0];
    }

    /** @return class-string<Tabulatable> */
    abstract public function tabulatableClass(): string;

    public static function tabulatorDisplayControllerClass(): ?string
    {
        return null;
    }
}
