<?php

namespace Ignite\Core\Entities;

use Illuminate\Support\Facades\Config;
use OwenIt\Auditing\Audit as AuditTrait;
use OwenIt\Auditing\Contracts\Audit as AuditContract;

class Audit extends Base implements AuditContract
{
    use AuditTrait;

    /**
     * {@inheritdoc}
     */
    protected $table = 'core_audit';

    /**
     * {@inheritdoc}
     */
    protected $casts = [
        'old_values' => 'json',
        'new_values' => 'json',
    ];

    /**
     * Get the readable name for the auditable class entity.
     *
     * @return string
     */
    public function getReadableEntityName()
    {
        return ucwords(snake_case(class_basename($this->auditable_type), ' '));
    }

    /**
     * Get the readable identifier for the audited record.
     *
     * @return string
     */
    public function getReadableIdentifier()
    {
        $join = ' ';
        $field = $this->auditable_type::getAuditFriendlyField();
        if (method_exists($this->auditable_type, 'getAuditFriendlyFieldJoinCharacter')) {
            $join = $this->auditable_type::getAuditFriendlyFieldJoinCharacter();
        }

        if (is_array($field)) {
            foreach ($field as $attribute) {
                $readableValue = $this->getReadableValueByAttributeKey($attribute);
                if (method_exists($this->auditable_type, 'getReadableValueByAttributeKey')) {
                    $readableValue = $this->auditable_type::getReadableValueByAttributeKey($attribute, $this);
                }

                $values[] = $readableValue;
            }
            return implode($join, $values);
        }

        return $this->getReadableValueByAttributeKey($field);
    }

    /**
     * Get a value from the correct value array by attribute.
     *
     * @param  string  $attribute
     * @param  object|null  $model
     * @return string
     */
    protected function getReadableValueByAttributeKey(string $attribute, object $model = null): string
    {
        if ($this->event === 'deleted') {
            return $this->old_values[$attribute] ?? $attribute;
        }

        return $this->new_values[$attribute] ?? $attribute;
    }

    /**
     * {@inheritdoc}
     */
    public function resolveData(): array
    {
        // Metadata
        $this->data = [
            'audit_id' => $this->id,
            'audit_event' => $this->event,
            'audit_url' => $this->url,
            'audit_ip_address' => $this->ip_address,
            'audit_user_agent' => $this->user_agent,
            'audit_created_at' => $this->serializeDate($this->created_at),
            'audit_updated_at' => $this->serializeDate($this->updated_at),
            'user_id' => $this->getAttribute(Config::get('audit.user.foreign_key', 'user_id')),
        ];

        if ($this->relationLoaded('user') && $this->user) {
            foreach ($this->user->attributesToArray() as $attribute => $value) {
                $this->data['user_'.$attribute] = $value;
            }
        }

        $this->metadata = array_keys($this->data);

        // Modified Auditable attributes
        foreach ($this->new_values as $key => $value) {
            $this->data['new_'.$key] = $value;
        }

        foreach ($this->old_values as $key => $value) {
            $this->data['old_'.$key] = $value;
        }

        $this->modified = array_diff_key(array_keys($this->data), $this->metadata);

        return $this->data;
    }
}
