<?php

namespace App\Services\Concerns;

use App\Models\FormHistory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;

trait LogsFormHistory
{
    private function logCreated(Model $model, string $module, array $newValues): void
    {
        $changes = $this->buildCreatedChanges($newValues);

        FormHistory::create([
            'causer_id' => Auth::id(),
            'module' => $module,
            'event' => 'created',
            'description' => "{$module} ditambahkan",
            'attribute_changes' => $changes ?: null,
        ]);
    }

    private function logUpdated(Model $model, string $module, array $oldValues, array $newValues): void
    {
        $changes = $this->buildUpdatedChanges($oldValues, $newValues);

        FormHistory::create([
            'causer_id' => Auth::id(),
            'module' => $module,
            'event' => 'updated',
            'description' => "{$module} diperbarui",
            'attribute_changes' => $changes ?: null,
        ]);
    }

    private function logDeleted(Model $model, string $module, array $oldValues): void
    {
        $changes = $this->buildDeletedChanges($oldValues);

        FormHistory::create([
            'causer_id' => Auth::id(),
            'module' => $module,
            'event' => 'deleted',
            'description' => "{$module} dihapus",
            'attribute_changes' => $changes ?: null,
        ]);
    }

    private function resolveItemName(array $item): string
    {
        $nameKeys = ['Nama Varian', 'Nama', 'name', 'variant', 'Variant', 'variant_name'];

        foreach ($nameKeys as $nameKey) {
            if (! empty($item[$nameKey])) {
                return (string) $item[$nameKey];
            }
        }

        return '?';
    }

    private function buildCreatedChanges(array $newValues): array
    {
        $changes = [];

        foreach ($newValues as $key => $value) {
            if (is_array($value)) {
                foreach ($value as $item) {
                    if (is_array($item)) {
                        $itemName = $this->resolveItemName($item);
                        foreach ($item as $subKey => $subValue) {
                            $changes["{$key}: {$itemName} — {$subKey}"] = ['new' => $subValue];
                        }
                    } else {
                        $changes["{$key}: {$item}"] = ['new' => null];
                    }
                }
            } else {
                $changes[$key] = ['new' => $value];
            }
        }

        return $changes;
    }

    private function buildUpdatedChanges(array $oldValues, array $newValues): array
    {
        $changes = [];
        $allKeys = array_unique(array_merge(array_keys($oldValues), array_keys($newValues)));

        foreach ($allKeys as $key) {
            $old = $oldValues[$key] ?? null;
            $new = $newValues[$key] ?? null;

            if (is_array($old) && is_array($new)) {
                $nestedChanges = $this->diffArray($old, $new, $key);
                $changes = array_merge($changes, $nestedChanges);
            } elseif ($old !== $new) {
                $changes[$key] = array_filter([
                    'old' => $old ?? null,
                    'new' => $new ?? null,
                ]);
            }
        }

        return $changes;
    }

    private function buildDeletedChanges(array $oldValues): array
    {
        $changes = [];

        foreach ($oldValues as $key => $value) {
            if (is_array($value)) {
                foreach ($value as $item) {
                    if (is_array($item)) {
                        $itemName = $this->resolveItemName($item);
                        foreach ($item as $subKey => $subValue) {
                            $changes["{$key}: {$itemName} — {$subKey}"] = ['old' => $subValue];
                        }
                    } else {
                        $changes["{$key}: {$item}"] = ['old' => null];
                    }
                }
            } else {
                $changes[$key] = ['old' => $value];
            }
        }

        return $changes;
    }

    private function diffArray(array $old, array $new, string $prefix = ''): array
    {
        $changes = [];

        $isAssociative = ! empty($old) && array_is_list($old) === false;

        if ($isAssociative) {
            $allKeys = array_unique(array_merge(array_keys($old), array_keys($new)));

            foreach ($allKeys as $key) {
                $fullKey = "{$prefix}.{$key}";

                if (isset($old[$key]) && is_array($old[$key]) && isset($new[$key]) && is_array($new[$key])) {
                    $nested = $this->diffArray($old[$key], $new[$key], $fullKey);
                    $changes = array_merge($changes, $nested);
                } else {
                    $oldVal = $old[$key] ?? null;
                    $newVal = $new[$key] ?? null;

                    if ($oldVal !== $newVal) {
                        $changes[$fullKey] = array_filter([
                            'old' => $oldVal ?? null,
                            'new' => $newVal ?? null,
                        ]);
                    }
                }
            }
        } else {
            $max = max(count($old), count($new));

            for ($i = 0; $i < $max; $i++) {
                $oldItem = $old[$i] ?? null;
                $newItem = $new[$i] ?? null;

                if (is_array($oldItem) && is_array($newItem)) {
                    $itemName = $this->resolveItemName($newItem);
                    $itemPrefix = "{$prefix}: {$itemName}";
                    $itemKeys = array_unique(array_merge(array_keys($oldItem), array_keys($newItem)));

                    foreach ($itemKeys as $subKey) {
                        $fullKey = "{$itemPrefix} — {$subKey}";
                        $oldVal = $oldItem[$subKey] ?? null;
                        $newVal = $newItem[$subKey] ?? null;

                        if ($oldVal !== $newVal) {
                            $changes[$fullKey] = array_filter([
                                'old' => $oldVal ?? null,
                                'new' => $newVal ?? null,
                            ]);
                        }
                    }
                } elseif ($oldItem !== $newItem) {
                    $itemName = $this->resolveItemName(is_array($oldItem) ? $oldItem : (is_array($newItem) ? $newItem : []));
                    $changes["{$prefix}: {$itemName}"] = array_filter([
                        'old' => $oldItem,
                        'new' => $newItem,
                    ]);
                }
            }
        }

        return $changes;
    }

    private function formatCurrency(int $value): string
    {
        return 'Rp ' . number_format($value, 0, ',', '.');
    }

    private function formatDate(?string $date, string $format = 'l, d F Y'): ?string
    {
        return $date ? \Carbon\Carbon::parse($date)->translatedFormat($format) : null;
    }

    private function formatDateTime(?string $datetime): ?string
    {
        return $datetime ? \Carbon\Carbon::parse($datetime)->translatedFormat('l, d F Y H:i') : null;
    }

    private function formatBoolean(?bool $value): ?string
    {
        return $value === null ? null : ($value ? 'Ya' : 'Tidak');
    }

    private function resolveRelation(Model $model, string $relation, string $attribute): ?string
    {
        $related = $model->{$relation};

        return $related?->{$attribute} ?? null;
    }
}
