<?php
namespace App\Services;

use App\Repositories\AuditLogRepository;
use App\Repositories\FieldAuditLogRepository;

class AuditService
{
    private $repo;
    private ?FieldAuditLogRepository $fieldAuditRepo;

    public function __construct(AuditLogRepository $repo, ?FieldAuditLogRepository $fieldAuditRepo = null)
    {
        $this->repo = $repo;
        $this->fieldAuditRepo = $fieldAuditRepo;
    }

    public function log(string $action, string $entityType, ?string $entityId, $snapshot = null, ?string $relatedPersonId = null): int
    {
        $snapshotJson = null;
        if ($snapshot !== null) {
            // Check if related person ID is inside snapshot (as a hack for existing calls)
            if ($relatedPersonId === null && is_array($snapshot) && isset($snapshot['_related_person_id'])) {
                $relatedPersonId = $snapshot['_related_person_id'];
                unset($snapshot['_related_person_id']);
            }
            $snapshotJson = json_encode($snapshot, JSON_UNESCAPED_UNICODE);
        }

        // Auto-detect if entity is person
        if ($relatedPersonId === null && $entityType === 'person' && $entityId) {
            $relatedPersonId = $entityId;
        }

        $actorName = $_SESSION['display_name'] ?? null;
        if (!$actorName) {
            $actorName = $_SESSION['name'] ?? null;
        }

        $actorIp = null;
        $xff = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? null;
        if (is_string($xff) && trim($xff) !== '') {
            $parts = array_map('trim', explode(',', $xff));
            $actorIp = $parts[0] ?? null;
        }
        if (!$actorIp) {
            $actorIp = $_SERVER['REMOTE_ADDR'] ?? null;
        }

        return $this->repo->create([
            'actor_user_id' => $_SESSION['user_id'] ?? null,
            'actor_didar_id' => $_SESSION['didar_id'] ?? null,
            'actor_name' => $actorName,
            'actor_ip' => $actorIp,
            'action' => $action,
            'entity_type' => $entityType,
            'entity_id' => $entityId,
            'related_person_didar_id' => $relatedPersonId,
            'snapshot_json' => $snapshotJson,
        ]);
    }

    /**
     * Log a specific field change
     */
    public function logFieldChange(string $entityType, string $entityId, string $fieldName, $oldValue, $newValue): ?int
    {
        if (!$this->fieldAuditRepo) {
            return null;
        }

        // Convert arrays/objects to JSON for storage
        if (is_array($oldValue) || is_object($oldValue)) {
            $oldValue = json_encode($oldValue, JSON_UNESCAPED_UNICODE);
        }
        if (is_array($newValue) || is_object($newValue)) {
            $newValue = json_encode($newValue, JSON_UNESCAPED_UNICODE);
        }

        $actorName = $_SESSION['display_name'] ?? $_SESSION['name'] ?? null;

        return $this->fieldAuditRepo->logChange([
            'entity_type' => $entityType,
            'entity_id' => $entityId,
            'field_name' => $fieldName,
            'old_value' => $oldValue,
            'new_value' => $newValue,
            'actor_didar_id' => $_SESSION['didar_id'] ?? null,
            'actor_name' => $actorName
        ]);
    }

    /**
     * Log multiple field changes at once
     */
    public function logFieldChanges(string $entityType, string $entityId, array $oldData, array $newData, array $fieldsToTrack = []): void
    {
        if (!$this->fieldAuditRepo) {
            return;
        }

        $actorDidarId = $_SESSION['didar_id'] ?? null;
        $actorName = $_SESSION['display_name'] ?? $_SESSION['name'] ?? null;

        // If no specific fields to track, track all changed fields
        $fieldsToCheck = !empty($fieldsToTrack) ? $fieldsToTrack : array_unique(array_merge(array_keys($oldData), array_keys($newData)));

        $changes = [];
        foreach ($fieldsToCheck as $field) {
            $oldVal = $oldData[$field] ?? null;
            $newVal = $newData[$field] ?? null;

            // Convert to string for comparison
            $oldStr = is_array($oldVal) ? json_encode($oldVal, JSON_UNESCAPED_UNICODE) : (string)$oldVal;
            $newStr = is_array($newVal) ? json_encode($newVal, JSON_UNESCAPED_UNICODE) : (string)$newVal;

            if ($oldStr !== $newStr) {
                $changes[$field] = ['old' => $oldStr, 'new' => $newStr];
            }
        }

        if (!empty($changes)) {
            $this->fieldAuditRepo->logChanges($entityType, $entityId, $changes, $actorDidarId, $actorName);
        }
    }

    /**
     * Get field change history for an entity
     */
    public function getFieldHistory(string $entityType, string $entityId, int $limit = 100): array
    {
        if (!$this->fieldAuditRepo) {
            return [];
        }

        return $this->fieldAuditRepo->getByEntity($entityType, $entityId, $limit);
    }
}
