<?php

declare(strict_types=1);

namespace apexl\Io\modules\tabulator\Tabulatable\ColumnCallback;

use apexl\entityCore\collections\EntityCollection;
use apexl\Io\includes\Entity;
use apexl\Io\interfaces\HasNiceNameInterface;
use apexl\Io\modules\tabulator\Interfaces\HasTabulatorViewInterface;
use apexl\Io\modules\tabulator\Interfaces\TabulatableColumnCallback;
use apexl\Io\modules\tabulator\Services\TabulatorFieldRenamer;
use DateTimeInterface;
use Money\Money;

final readonly class SimpleField implements TabulatableColumnCallback
{
    public function __construct(
        private TabulatorFieldRenamer $fieldRenamer,
        private FormatMoney $formatMoney,
        private null|array|int|float|string $default = null,
        private ?string $override = null
    ) {}

    public function __invoke(HasTabulatorViewInterface $entity, string $field): mixed
    {
        $field = $this->fieldRenamer->rename($field);

        if (str_contains($field, '__')) {
            return $this->nestedValue($entity, $field);
        }

        $value = $entity->{$this->override ?? $field};

        if ($value instanceof Entity) {
            return $value->titleField();
        }

        if ($value instanceof HasNiceNameInterface) {
            return $value->getNiceName();
        }

        if ($value instanceof DateTimeInterface) {
            return $this->formattedDateTime($value);
        }

        if ($value instanceof Money) {
            return ($this->formatMoney)($entity, $field);
        }

        return $value ?? $this->default;
    }

    function nestedValue(HasTabulatorViewInterface $entity, string $field): mixed
    {
        $fields = explode('__', $field);

        $value = $entity->{$fields[0]};

        if ($value === null) {
            return null;
        }

        if ($value instanceof DateTimeInterface) {
            return $this->formattedDateTime($value);
        }

        if ($value instanceof Entity) {
            return $this->findNestedValue($value, array_slice($fields, 1));
        }

        if ($value instanceof EntityCollection) {
            return $value->map(function ($item) use ($fields) {
                return $this->findNestedValue($item, array_slice($fields, 1));
            })->toArray();
        }

        if ($value instanceof HasNiceNameInterface) {
            return $value->getNiceName();
        }

        return null;
    }

    private function formattedDateTime(DateTimeInterface $value): string
    {
        if ($value->format('H:i:s') === '00:00:00') {
            return $value->format('d/m/Y');
        }

        return $value->format('d/m/Y H:i');
    }

    private function findNestedValue(object|array $value, array $fields)
    {
        $key = array_shift($fields);

        $value = $value->{$key};

        if ($value instanceof EntityCollection) {
            return $value->map(fn($item) => $this->findNestedValue($item, $fields))->toArray();
        }

        if ($value instanceof DateTimeInterface) {
            return $this->formattedDateTime($value);
        }

        if ($value === null) {
            return null;
        }

        if (empty($fields)) {
            return $value instanceof HasNiceNameInterface ? $value->getNiceName() : $value;
        }

        return $this->findNestedValue($value, $fields);
    }


}

