<?php

declare(strict_types=1);

namespace App\Nova\Actions;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Maatwebsite\LaravelNovaExcel\Actions\DownloadExcel as BaseDownloadExcel;

// Fixes Nova 5 incompatibility where field names are PendingTranslation objects instead of strings.
final class DownloadExcel extends BaseDownloadExcel
{
    protected $onlyIndexFields = false;
    /**
     * @param  Model|mixed  $row
     */
    public function map($row): array
    {
        $only   = array_map('strval', $this->getOnly());
        $except = $this->getExcept();

        if ($row instanceof Model) {
            if (!$this->onlyIndexFields && $except === null && (!is_array($only) || count($only) === 0)) {
                $except = $row->getHidden();
            }

            $row->setHidden([]);
            $row = $this->replaceFieldValuesWhenOnResource($row, $only);
        }

        if (is_array($only) && count($only) > 0) {
            $row = Arr::only($row, $only);
        }

        if (is_array($except) && count($except) > 0) {
            $row = Arr::except($row, $except);
        }

        return $row;
    }

    protected function replaceFieldValuesWhenOnResource(Model $model, array $only = []): array
    {
        $resource = $this->resolveResource($model);
        $fields   = $this->resourceFields($resource);

        $row = [];
        foreach ($fields as $field) {
            if (!$this->isExportableField($field)) {
                continue;
            }

            if (\in_array($field->attribute, $only, true)) {
                $row[$field->attribute] = $field->value;
            } elseif (\in_array((string) $field->name, $only, true)) {
                $row[(string) $field->name] = $field->value;
            }
        }

        foreach (array_diff($only, array_keys($row)) as $attribute) {
            if ($model->{$attribute}) {
                $row[$attribute] = $model->{$attribute};
            } else {
                $row[$attribute] = '';
            }
        }

        $row = array_merge(array_flip($only), $row);

        return $row;
    }
}
