<?php

namespace Nurmuhammet\InlineRelationship;

use Exception;
use Laravel\Nova\Fields\Field;
use Laravel\Nova\Fields\SupportsDependentFields;

class InlineRelationship extends Field
{
    use SupportsDependentFields;

    /**
     * The field's component.
     *
     * @var string
     */
    public $component = 'inline-relationship';

    /**
     * Related resource name
     */
    protected string $relatedResourceName;

    /**
     * Resource relationship attribute to related resource
     */
    protected string $relationshipAttribute;

    /**
     * Related resource
     */
    protected string $relatedResource;

    /**
     * Relationship type
     */
    protected string $relationshipType;

    /**
     * Create a new field.
     *
     * @param  string|null  $attribute
     * @param  class-string<\Laravel\Nova\Resource>|null  $resource
     * @return void
     */
    public function __construct(string $name, string $attribute, string $resource)
    {
        parent::__construct($name, $attribute);

        $this->relatedResourceName = $name;
        $this->relationshipAttribute = $attribute;
        $this->relatedResource = $resource;
        $this->relatedResourceURI = $resource::uriKey();
        $this->relationshipType = $this->guessRelationshipType();

        $this->validate();

        $this->fullWidth();
        $this->transformDataForFrontend();
    }

    /**
     * Validate user's arguments
     */
    public function validate(): void
    {
        in_array($this->relationshipType, $this->allowedRelationships())
            ? true
            : throw new Exception("Selected relationship ({$relationshipType}) is not allowed");
    }

    /**
     * Alloed relationships
     */
    public function allowedRelationships(): array
    {
        return [
            'Illuminate\\Database\\Eloquent\\Relations\\HasMany',
        ];
    }

    /**
     * Guess relationship type from related resource
     */
    public function guessRelationshipType(): string
    {
        return get_class((new $this->relatedResource::$model)->{$this->relationshipAttribute}());
    }

    /**
     * Formatted relationship name
     */
    public function formattedRelatioshipName(): string
    {
        return match ($this->relationshipType) {
            'Illuminate\\Database\\Eloquent\\Relations\\HasMany' => 'hasMany',
        };
    }

    /**
     * Transform data to frontend
     */
    public function transformDataForFrontend(): self
    {
        return $this->withMeta([
            'singularLabel' => $this->relatedResource::singularLabel(),
            'relatedResourceName' => $this->relatedResourceName,
            'relationshipAttribute' => $this->relationshipAttribute,
            'relatedResource' => $this->relatedResource,
            'relatedResourceURI' => $this->relatedResourceURI,
            'relationshipType' => $this->formattedRelatioshipName(),
        ]);
    }
}
