<?php

declare(strict_types=1);

namespace Builder\Core\Http\Controllers\Resource;

use Builder\Core\Foundation\Contracts\Translatable;
use Builder\Core\Foundation\Registry;
use Builder\Core\Foundation\Resources\FieldHandlerRegistry;
use Builder\Core\Foundation\Resources\RecordAction;
use Builder\Core\Foundation\Revisions\RevisionService;
use Builder\Core\Http\Controllers\Concerns\HasResourceResolving;
use Builder\Core\Models\Revision;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;

final class ResourceEditController
{
    use HasResourceResolving;

    public function __construct(
        private readonly Registry $registry,
        private readonly RevisionService $revisionService,
        private readonly FieldHandlerRegistry $fieldHandlerRegistry,
    ) {}

    public function __invoke(Request $request, string $resource, int|string $id): Response
    {
        $definition = $this->resolveOrFail($resource);
        $this->authorizeResource($request, $definition, 'edit');
        $model = $definition->getModel();

        $record = $model::with($definition->getEagerLoad())->findOrFail($id);

        $isTranslatable = $record instanceof Translatable;
        $locale = $isTranslatable ? $this->resolveContentLocale($request) : null;

        $recordData = $definition->getResource()->getRecordForEdit($record);

        if ($isTranslatable && $locale) {
            $translation = $record->getTranslation($locale);

            foreach ($definition->getTranslatableFieldNames() as $attr) {
                $recordData[$attr] = $translation->{$attr} ?? null;
            }
        }

        $recordActions = array_values(array_map(
            fn (RecordAction $a): array => $a->toArray(),
            array_filter(
                $definition->getRecordActions(),
                fn (RecordAction $a): bool => $a->isVisibleFor($record),
            ),
        ));

        if ($definition->isHierarchical()) {
            $parentId = $record->getAttribute($definition->getParentField());
            $parentModel = $parentId !== null
                ? ($record->relationLoaded('parent') ? $record->getRelation('parent') : $definition->getModel()::find($parentId))
                : null;

            if ($parentModel !== null) {
                $parentSlug = $parentModel instanceof Translatable && $locale !== null
                    ? $parentModel->getTranslation($locale)?->getAttribute('slug')
                    : $parentModel->getAttribute('slug');

                $recordData['_parentSlug'] = $parentSlug;
            } else {
                $recordData['_parentSlug'] = null;
            }
        }

        foreach ($this->fieldHandlerRegistry->all() as $componentName => $handlerInterface) {
            $handler = $this->fieldHandlerRegistry->resolve($componentName);

            if ($handler === null) {
                continue;
            }

            $fields = $definition->getFieldDefinitionsByComponent($componentName);

            if ($fields === []) {
                continue;
            }

            $handler->loadFields($record, $fields, $locale);

            foreach (array_keys($fields) as $fieldName) {
                $recordData[$fieldName] = $record->getAttribute($fieldName);
            }
        }

        $revisionCount = $definition->isRevisable()
            ? Inertia::defer(fn (): int => Revision::query()
                ->where('revisable_type', $model)
                ->where('revisable_id', $id)
                ->count())
            : null;

        return Inertia::render('Resource/Form', [
            'resource' => $definition->toArray(),
            'record' => $recordData,
            'record_actions' => $recordActions,
            'can_delete' => $this->canDeleteRecord($definition, $record),
            'currentLocale' => $locale,
            'availableLocales' => $isTranslatable ? $this->resolveAvailableLanguages() : [],
            'revision_count' => $revisionCount,
        ]);
    }
}
