<?php

namespace App\Services\History;

use App\Models\Enums\ActionObjectType;
use Illuminate\Database\Eloquent\Model;

class ModelChangeDetector
{
    public static function detector(ActionObjectType $objectType, Model $model): array
    {
        $detector = $objectType->detectorClassName();

        if (! $detector) {
            return [];
        }

        $fields = call_user_func([$detector, "fields"]);
        $diffFields = call_user_func([$detector, "diffFields"]);
        $arrayFields = call_user_func([$detector, "arrayFields"]);

        if (!$fields) {
            return [];
        }

        $items = [];
        foreach ($fields as $field) {
            if (! $model->isDirty($field) && ! in_array($field, $diffFields)) {
                continue;
            }
            if (in_array($field, $arrayFields)) {
                $items = array_merge($items, self::getArrayChange($model, $field));
            } else {
                $change = self::getChange($model, $field);
                if ($change['diff']) {
                    $items[] = $change;
                }
            }
        }

        return $items;
    }

    public static function getChange(Model $model, $field): array
    {
        return [
            'old' => is_array($model->getOriginal($field)) ? json_encode($model->getOriginal($field)) : $model->getOriginal($field),
            'field' => $field,
            'new' => is_array($model->$field) ? json_encode($model->$field) : $model->$field,
            'diff' => text_diff($model->getOriginal($field) ?? '', $model->$field ?? '')
        ];
    }

    public static function getArrayChange(Model $model, $field): array
    {
        $items = [];
        $oldArr = $model->getOriginal($field);
        $newArr = $model->$field;
        if (!is_array($newArr) || !is_object($newArr)) {
            return [];
        }
        foreach ($newArr as $field => $newValue) {
            $oldValue = $oldArr[$field] ?? null;
            $diff = text_diff($oldValue ?? '', $newValue ?? '');
            if (!$diff) {
                continue;
            }
            $items[] = [
                'old' => is_array($oldValue) ? json_encode($oldValue, JSON_UNESCAPED_UNICODE) : $oldValue,
                'field' => $field,
                'new' => is_array($newValue) ? json_encode($newValue, JSON_UNESCAPED_UNICODE) : $newValue,
                'diff' => $diff
            ];
        }
        return $items;
    }
}