<?php

namespace App\Services\Import;

use App\Models\ImportEntity;
use App\Services\Import\Contracts\EntityHandlerInterface;
use Illuminate\Support\Facades\Validator;

abstract class BaseEntityHandler implements EntityHandlerInterface
{
    protected ?ImportEntity $entityConfig;

    public function __construct(?ImportEntity $entityConfig = null)
    {
        $this->entityConfig = $entityConfig;
    }

    /**
     * Validate mapped data using configuration rules.
     */
    public function validate(array $mapped): array
    {
        $rules = $this->entityConfig?->validation_rules ?? [];

        if (empty($rules)) {
            return ['valid' => true, 'errors' => []];
        }

        $validator = Validator::make($mapped, $rules);

        if ($validator->fails()) {
            return [
                'valid' => false,
                'errors' => $validator->errors()->all(),
            ];
        }

        return ['valid' => true, 'errors' => []];
    }

    /**
     * Get processing options from config.
     */
    protected function getOption(string $key, mixed $default = null): mixed
    {
        return $this->entityConfig?->processing_options[$key] ?? $default;
    }

    /**
     * Determine if a field has changed.
     */
    protected function hasChanged($model, string $field, mixed $newValue): bool
    {
        $current = $model->{$field};

        if (is_null($newValue) && is_null($current)) {
            return false;
        }

        return $current != $newValue;
    }

    /**
     * Track which fields were applied/changed.
     */
    protected function trackAppliedFields($model, array $payload): array
    {
        $applied = [];

        foreach ($payload as $field => $value) {
            if ($this->hasChanged($model, $field, $value)) {
                $applied[] = $field;
            }
        }

        return $applied;
    }

    /**
     * Default implementation returns null - override in specific handlers.
     */
    public function resolve(array $mapped, array $context = []): mixed
    {
        return null;
    }
}
