<?php

namespace App\Services;

use App\Models\AuditTrail;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Jenssegers\Agent\Agent;

class AuditTrailService
{
    public function log(
        string $moduleType,
        string $moduleName,
        ?int $moduleId = null,
        string $action,
        ?Model $model = null,
        ?array $oldData = null,
        ?array $newData = null,
        ?User $user = null
    ): void {
        $user = $user ?? auth()->user();

        if (!$user) {
            $this->logWithoutUser(
                $moduleType,
                $moduleName,
                $action,
                $model,
                $oldData,
                $newData
            );
            return;
        }

        $agent = new Agent();

        $device = request()->header('X-Device-Name', 'Unknown Device');
        $platform = request()->header('X-Platform', 'Unknown OS');
        $browser = $agent->browser() ?: 'Mobile App';

        $deviceType = 'desktop';

        if ($agent->isMobile()) {
            $deviceType = 'mobile';
        } elseif ($agent->isTablet()) {
            $deviceType = 'tablet';
        }

        $userAgentDetails = sprintf(
            "%s | %s | %s | %s | %s",
            request()->userAgent(),
            $deviceType,
            $device,
            $platform,
            $browser
        );

        $logData = [
            "action" => $action,
            "action_by" => $user->id,
            "action_by_name" =>
            $user->id_prefix .
                " - " .
                $user->id_no .
                " - " .
                $user->first_name .
                " " .
                $user->last_name,
            "module_type" => $moduleType,
            "module_name" => $moduleName,
            "module_id" => $moduleId,
            "log_info" => $this->generateLogInfo(
                $action,
                $moduleName,
                $model,
                $oldData,
                $newData,
                $user
            ),
            "ip_address" => request()->ip(),
            "user_agent" => $userAgentDetails,
        ];

        $created = __("models.lc_created");
        $updated = __("models.lc_updated");
        $archived = __("models.lc_archived");
        $restored = __("models.lc_restored");

        switch ($action) {
            case $created:
                $logData["new_data"] =
                    $newData ?? ($model ? $model->getAttributes() : null);
                $logData["previous_data"] = null;
                break;

            case $updated:
                $logData["previous_data"] = $oldData;
                $logData["new_data"] =
                    $newData ?? ($model ? $model->getAttributes() : null);
                break;

            case $restored:
            case $archived:
                $logData["previous_data"] =
                    $oldData ?? ($model ? $model->getAttributes() : null);
                $logData["new_data"] = null;
                break;

            case "login":
            case "logout":
                $logData["new_data"] = $newData;
                $logData["previous_data"] = null;
                break;

            case "synced":
                $logData["previous_data"] = $oldData;
                $logData["new_data"]      = $newData ?? ($model ? $model->getAttributes() : null);
                break;
        }

        AuditTrail::create($logData);
    }

    protected function logWithoutUser(
        string $moduleType,
        string $moduleName,
        string $action,
        ?Model $model,
        ?array $oldData,
        ?array $newData
    ): void {
        $logData = [
            "action" => $action,
            "action_by" => null,
            "action_by_name" => "Guest/Unauthenticated",
            "module_type" => $moduleType,
            "module_name" => $moduleName,
            "log_info" => $this->generateLogInfo(
                $action,
                $moduleName,
                $model,
                $oldData,
                $newData,
                null
            ),
            "ip_address" => request()->ip(),
            "user_agent" => request()->userAgent(),
            "previous_data" => $oldData,
            "new_data" => $newData,
        ];

        AuditTrail::create($logData);
    }

    protected function generateLogInfo(
        string $action,
        string $moduleName,
        ?Model $model,
        ?array $oldData,
        ?array $newData,
        ?User $user
    ): string {
        $userName = $user
            ? $user->first_name . " " . $user->last_name
            : "Guest";
        $modelId = $model ? $model->id : "N/A";

        $created = __("models.lc_created");
        $updated = __("models.lc_updated");
        $archived = __("models.lc_archived");
        $restored = __("models.lc_restored");

        switch (strtolower($action)) {
            case "login":
                return $userName . " logged in";

            case "logout":
                return $userName . " logged out";

            case "login_failed":
                $username = $newData["username"] ?? "Unknown";
                return "Failed login attempt for username: {$username}";

            case $created:
                $title =
                    $newData["title"] ?? ($newData["name"] ?? "ID {$modelId}");
                return "{$userName} created new {$moduleName} '{$title}'";

            case $updated:
                return "{$userName} updated {$moduleName} (ID: {$modelId})";

            case $archived:
                $title =
                    $oldData["title"] ?? ($oldData["name"] ?? "ID {$modelId}");
                return "{$userName} archived {$moduleName} '{$title}'";

            case $restored:
                $title =
                    $oldData["title"] ?? ($oldData["name"] ?? "ID {$modelId}");
                return "{$userName} restored {$moduleName} '{$title}'";

            case "password_changed":
                return "{$userName} changed their password";

            case "password_reset":
                return "{$userName}'s password was reset";

            case "status_changed_to_saved":
                $ids = $newData["ids"] ?? [];
                $idList = implode(", ", $ids);
                $idCount = count($ids);
                return "{$userName} changed status to 'saved' for {$idCount} loading record(s) (IDs: {$idList})";

            case "voided":
                $loadingId = $newData["loading_id"] ?? "N/A";
                $batchId = $newData["batch_id"] ?? null;
                $batchNo = $newData["batch_no"] ?? null;
                $message = "{$userName} voided loading record (ID: {$loadingId})";
                if ($batchId && $batchNo) {
                    $message .= " and its batch (ID: {$batchId} - {$batchNo})";
                }
                return $message;

            case "synced":
                $action = $oldData ? "updated via sync" : "created via sync";
                return "{$userName} {$action} {$moduleName} (ID: {$modelId})";

            default:
                return "{$userName} performed {$action} on {$moduleName} (ID: {$modelId})";
        }
    }
}
