<?php

namespace App\Domains\Analytics\Jobs;

use App\Domains\Analytics\Events\ClickRecorded;
use App\Domains\Analytics\Models\Click;
use App\Domains\Link\Models\Link;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redis;

class RecordClickJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable;

    /**
     * @param  array<string, array<int, string>>  $headers
     * @param  array<string, string>  $queryParams
     */
    public function __construct(
        public readonly int $linkId,
        public readonly string $ip,
        public readonly ?string $userAgent,
        public readonly array $headers,
        public readonly array $queryParams = [],
    ) {}

    public function handle(): void
    {
        $link = Link::find($this->linkId);
        if (! $link) {
            return;
        }

        $ipHash = $this->hashIp($this->ip);
        $device = $this->detectDevice($this->userAgent ?? '');

        $click = Click::create([
            'link_id' => $this->linkId,
            'workspace_id' => $link->workspace_id,
            'clicked_at' => now(),
            'ip_hash' => $ipHash,
            'device' => $device,
            'os' => $this->detectOs($this->userAgent ?? ''),
            'browser' => $this->detectBrowser($this->userAgent ?? ''),
            'referrer_host' => $this->extractHost($this->headers['referer'][0] ?? null),
            'utm_source' => $this->queryParams['utm_source'] ?? null,
            'utm_medium' => $this->queryParams['utm_medium'] ?? null,
            'utm_campaign' => $this->queryParams['utm_campaign'] ?? null,
            'language' => substr($this->headers['accept-language'][0] ?? 'de', 0, 10),
        ]);

        // Increment Redis counters
        $date = now()->format('Y-m-d');
        Redis::incr("clicks:{$this->linkId}:{$date}");
        Redis::incr("clicks:{$link->workspace_id}:monthly:".now()->format('Ym'));

        // Broadcast event for live dashboard
        event(new ClickRecorded($click));
    }

    private function hashIp(string $ip): string
    {
        $salt = Cache::remember('ip_salt:'.today()->format('Y-m-d'), 86400, fn () => bin2hex(random_bytes(16)));

        return hash('sha256', $ip.$salt);
    }

    private function detectDevice(string $ua): string
    {
        $ua = strtolower($ua);
        if (str_contains($ua, 'bot') || str_contains($ua, 'crawler') || str_contains($ua, 'spider')) {
            return 'bot';
        }
        if (preg_match('/mobile|iphone|android.*mobile|windows phone/i', $ua)) {
            return 'mobile';
        }
        if (preg_match('/ipad|android(?!.*mobile)|tablet/i', $ua)) {
            return 'tablet';
        }
        if (strlen($ua) === 0) {
            return 'unknown';
        }

        return 'desktop';
    }

    private function detectOs(string $ua): ?string
    {
        if (stripos($ua, 'iPhone') !== false || stripos($ua, 'iPad') !== false) {
            return 'ios';
        }
        if (stripos($ua, 'Android') !== false) {
            return 'android';
        }
        if (stripos($ua, 'Windows') !== false) {
            return 'windows';
        }
        if (stripos($ua, 'Mac OS') !== false) {
            return 'macos';
        }
        if (stripos($ua, 'Linux') !== false) {
            return 'linux';
        }

        return null;
    }

    private function detectBrowser(string $ua): ?string
    {
        if (stripos($ua, 'Edge') !== false || stripos($ua, 'Edg/') !== false) {
            return 'edge';
        }
        if (stripos($ua, 'Chrome') !== false) {
            return 'chrome';
        }
        if (stripos($ua, 'Firefox') !== false) {
            return 'firefox';
        }
        if (stripos($ua, 'Safari') !== false) {
            return 'safari';
        }

        return null;
    }

    private function extractHost(?string $url): ?string
    {
        if (! $url) {
            return null;
        }
        $parsed = parse_url($url);

        return $parsed['host'] ?? null;
    }
}
