<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Collection;
use Mtc\MercuryDataModels\Audit;
use Mtc\MercuryDataModels\PropertyAttributeValue;

class AuditableResource extends JsonResource
{
    public static $wrap = '';

    private string $auditableType;
    private mixed $auditableId;

    public function __construct(string $auditableType, mixed $auditableId)
    {
        $this->auditableType = $auditableType;
        $this->auditableId = $auditableId;
        parent::__construct(null);
    }

    public function toArray($request): array
    {
        $audits = $this->fetchAudits()
            ->groupBy(fn(Audit $audit) => $audit->user_id . '_' . $audit->created_at->format('Y-m-d H:i:s'))
            ->map(fn($group) => $this->mergeAuditGroup($group))
            ->values()
            ->take(50);

        return [
            'audits' => $audits,
        ];
    }

    private function fetchAudits(): Collection
    {
        $query = Audit::query()
            ->where(function ($q) {
                $q->where('auditable_type', $this->auditableType)
                    ->where('auditable_id', $this->auditableId);
            });

        $related = $this->getRelatedAuditableIds();

        if ($related !== null && $related['ids']->isNotEmpty()) {
            $query->orWhere(function ($q) use ($related) {
                $q->where('auditable_type', $related['type'])
                    ->whereIn('auditable_id', $related['ids']);
            });
        }

        return $query
            ->with(['user', 'auditable'])
            ->orderByDesc('created_at')
            ->limit(100)
            ->get();
    }

    private function getRelatedAuditableIds(): ?array
    {
        return match ($this->auditableType) {
            'property' => [
                'type' => 'property-attribute',
                'ids' => PropertyAttributeValue::query()
                    ->where('property_id', $this->auditableId)
                    ->pluck('id'),
            ],
            default => null,
        };
    }

    private function mergeAuditGroup($group): array
    {
        $first = $group->first();
        $mergedOld = [];
        $mergedNew = [];

        foreach ($group as $audit) {
            $prefix = $this->getAuditPrefix($audit);

            $oldValues = is_string($audit->old_values)
                ? json_decode($audit->old_values, true) ?? []
                : ($audit->old_values ?? []);
            $newValues = is_string($audit->new_values)
                ? json_decode($audit->new_values, true) ?? []
                : ($audit->new_values ?? []);

            foreach ($oldValues as $key => $value) {
                $mergedOld[$prefix . $key] = $value;
            }
            foreach ($newValues as $key => $value) {
                $mergedNew[$prefix . $key] = $value;
            }
        }

        return [
            'id' => $first->id,
            'event' => $first->event,
            'created_at' => $first->created_at->format('d/m/Y H:i'),
            'user_name' => $first->user?->name ?? 'System',
            'old_values' => $mergedOld,
            'new_values' => $mergedNew,
        ];
    }

    private function getAuditPrefix(Audit $audit): string
    {
        return match ($audit->auditable_type) {
            'property-attribute' => ($audit->auditable?->slug ?? 'attr') . '.',
            default => '',
        };
    }
}
