<?php
declare(strict_types=1);

namespace App\Services\Security;

use App\Models\SecurityScanLog;
use App\Models\Setting;
use Throwable;

class ZaloroxShield
{
    private LinkScanner $linkScanner;
    private ContentModerator $contentModerator;

    public function __construct(private array $config)
    {
        $this->linkScanner = new LinkScanner($config);
        $this->contentModerator = new ContentModerator(new ForbiddenWordChecker($config['forbidden_words'] ?? []));
    }

    public function scanLink(string $url, ?int $userId = null, ?string $targetType = null, ?int $targetId = null): array
    {
        $settings = $this->getSettings();

        if (!$this->settingEnabled($settings, 'shield_enabled') || !$this->settingEnabled($settings, 'shield_link_scan_enabled')) {
            $result = $this->disabledResult('link_scan_disabled');
        } else {
            $result = $this->applyPolicy($this->linkScanner->scan($url), $settings);
        }

        $this->logScan($result, [
            'user_id' => $userId,
            'target_type' => $targetType ?? 'link',
            'target_id' => $targetId,
            'scan_type' => 'link',
            'input_value' => $url,
        ]);

        return $result;
    }

    public function scanContent(string $content, string $targetType, ?int $userId = null, ?int $targetId = null): array
    {
        $settings = $this->getSettings();
        $scanToggle = match ($targetType) {
            'comment' => 'shield_comment_scan_enabled',
            'message' => 'shield_message_scan_enabled',
            default => 'shield_content_scan_enabled',
        };

        if (!$this->settingEnabled($settings, 'shield_enabled') || !$this->settingEnabled($settings, $scanToggle)) {
            $result = $this->disabledResult($scanToggle . '_disabled');
        } else {
            $result = $this->applyPolicy($this->contentModerator->scan($content), $settings);
        }

        $this->logScan($result, [
            'user_id' => $userId,
            'target_type' => $targetType,
            'target_id' => $targetId,
            'scan_type' => 'content',
            'input_value' => $content,
        ]);

        return $result;
    }

    public function scanText(string $text): array
    {
        return $this->scanContent($text, 'text');
    }

    public function scanComment(string $comment, ?int $userId = null, ?int $commentId = null): array
    {
        return $this->scanContent($comment, 'comment', $userId, $commentId);
    }

    public function scanMessage(string $message, ?int $userId = null, ?int $messageId = null): array
    {
        // TODO: Mesajlasma akisi tamamlandiginda MessageController bu metodu kullanacak.
        return $this->scanContent($message, 'message', $userId, $messageId);
    }

    public function scanModContent(string $title, string $description, ?int $userId = null, ?int $modId = null): array
    {
        return $this->scanContent(trim($title . "\n" . $description), 'mod', $userId, $modId);
    }

    public function scanMusicContent(string $title, string $description, ?int $userId = null, ?int $musicId = null): array
    {
        // TODO: Muzik yukleme akisi tamamlandiginda music title/aciklama kontrolu buraya baglanacak.
        return $this->scanContent(trim($title . "\n" . $description), 'music', $userId, $musicId);
    }

    public function scanProfileBio(string $bio, ?int $userId = null): array
    {
        // TODO: Profil duzenleme akisi tamamlandiginda profil aciklamasi bu metoda baglanacak.
        return $this->scanContent($bio, 'profile', $userId, $userId);
    }

    public function scanCommunityPost(string $content, ?int $userId = null, ?int $postId = null): array
    {
        // TODO: Topluluk gonderileri Bolum 5+ kapsaminda gelistirilince bu metoda baglanacak.
        return $this->scanContent($content, 'community_post', $userId, $postId);
    }

    public function logScan(array $result, array $meta = []): int
    {
        try {
            return (new SecurityScanLog())->create([
                'user_id' => $meta['user_id'] ?? null,
                'target_type' => $meta['target_type'] ?? null,
                'target_id' => $meta['target_id'] ?? null,
                'scan_type' => $meta['scan_type'] ?? 'content',
                'input_value' => $this->trimForLog((string) ($meta['input_value'] ?? '')),
                'risk_score' => (int) ($result['risk_score'] ?? 0),
                'status' => (string) ($result['status'] ?? 'safe'),
                'reasons' => $result['reasons'] ?? [],
                'action_taken' => (string) ($result['action_taken'] ?? 'allow'),
            ]);
        } catch (Throwable) {
            return 0;
        }
    }

    public function getSettings(): array
    {
        try {
            return (new Setting())->getShieldSettings();
        } catch (Throwable) {
            return Setting::shieldDefaults();
        }
    }

    private function applyPolicy(array $result, array $settings): array
    {
        $riskScore = min(100, max(0, (int) ($result['risk_score'] ?? 0)));
        $reviewThreshold = min(100, max(0, (int) ($settings['shield_review_threshold'] ?? 31)));
        $blockThreshold = min(100, max($reviewThreshold, (int) ($settings['shield_block_threshold'] ?? 61)));

        $status = 'safe';
        if ($riskScore >= $blockThreshold) {
            $status = 'blocked';
        } elseif ($riskScore >= $reviewThreshold) {
            $status = 'review';
        }

        $action = match ($status) {
            'blocked' => $this->settingEnabled($settings, 'shield_auto_block') ? 'blocked' : 'pending_review',
            'review' => $this->settingEnabled($settings, 'shield_auto_pending') ? 'pending_review' : 'allow',
            default => 'allow',
        };

        $reasons = $result['reasons'] ?? [];
        if (!is_array($reasons)) {
            $reasons = [(string) $reasons];
        }

        return [
            'risk_score' => $riskScore,
            'status' => $status,
            'action_taken' => $action,
            'reasons' => array_values(array_unique(array_filter(array_map('strval', $reasons)))),
        ];
    }

    private function disabledResult(string $reason): array
    {
        return [
            'risk_score' => 0,
            'status' => 'safe',
            'action_taken' => 'allow',
            'reasons' => [$reason],
        ];
    }

    private function settingEnabled(array $settings, string $key): bool
    {
        return (int) ($settings[$key] ?? 0) === 1;
    }

    private function trimForLog(string $value): string
    {
        $value = trim(preg_replace('/\s+/', ' ', $value) ?: '');

        if (function_exists('mb_substr')) {
            return mb_substr($value, 0, 500);
        }

        return substr($value, 0, 500);
    }
}
