<?php
declare(strict_types=1);

namespace App\Services\Security;

use App\Core\Database;
use PDO;
use Throwable;

class MusicCopyrightScanner
{
    public function __construct(private array $config = [], private ?PDO $pdo = null)
    {
    }

    public function scanUpload(array $file, array $meta): array
    {
        $title = (string) ($meta['title'] ?? '');
        $artist = (string) ($meta['artist_name'] ?? '');
        $description = (string) ($meta['description'] ?? '');
        $storedPath = (string) ($meta['stored_path'] ?? ($file['tmp_name'] ?? ''));
        $hash = $storedPath !== '' ? $this->generateFileHash($storedPath) : '';
        $duplicate = $hash !== '' ? $this->checkDuplicateHash($hash) : ['duplicate' => false];
        $keywords = $this->checkCopyrightKeywords($title, $artist, $description);
        $risk = (int) ($keywords['risk_score'] ?? 0);
        $reasons = (array) ($keywords['reasons'] ?? []);
        $status = 'clean';

        if (empty($meta['artist_approved'])) {
            $risk = max($risk, 55);
            $reasons[] = 'Artist Connect onayi yok.';
        }

        if (empty($meta['rights_confirmed'])) {
            $risk = max($risk, 65);
            $reasons[] = 'Hak sahipligi onayi bulunmuyor.';
        }

        if (!empty($duplicate['duplicate'])) {
            $status = 'duplicate';
            $risk = max($risk, 82);
            $reasons[] = 'Ayni audio hash daha once yuklenmis.';
        }

        if ($risk >= 85) {
            $status = $status === 'duplicate' ? 'duplicate' : 'blocked';
        } elseif ($risk >= 45 && $status === 'clean') {
            $status = 'review';
        }

        return [
            'track_id' => $meta['track_id'] ?? null,
            'user_id' => $meta['user_id'] ?? null,
            'file_hash' => $hash,
            'title' => $title,
            'artist_name' => $artist,
            'status' => $status,
            'risk_score' => $risk,
            'reasons' => array_values(array_unique($reasons)),
            'provider' => 'local_hash_keyword',
            'duplicate_track_id' => $duplicate['track_id'] ?? null,
        ];
    }

    public function generateFileHash(string $path): string
    {
        $absolute = $this->absolutePath($path);
        if ($absolute === '' || !is_file($absolute)) {
            return '';
        }

        return hash_file('sha256', $absolute) ?: '';
    }

    public function checkDuplicateHash(string $hash): array
    {
        if ($hash === '') {
            return ['duplicate' => false];
        }

        try {
            $statement = $this->db()->prepare(
                'SELECT track_id, user_id, status, created_at
                 FROM music_copyright_checks
                 WHERE file_hash = :hash
                 ORDER BY id ASC
                 LIMIT 1'
            );
            $statement->execute(['hash' => $hash]);
            $row = $statement->fetch();

            if (!$row) {
                return ['duplicate' => false];
            }

            return [
                'duplicate' => true,
                'track_id' => isset($row['track_id']) ? (int) $row['track_id'] : null,
                'user_id' => isset($row['user_id']) ? (int) $row['user_id'] : null,
                'status' => (string) ($row['status'] ?? ''),
            ];
        } catch (Throwable) {
            return ['duplicate' => false];
        }
    }

    public function checkCopyrightKeywords(string $title, string $artist, string $description): array
    {
        $text = $this->normalize($title . ' ' . $artist . ' ' . $description);
        $rules = [
            'official audio' => 25,
            'official video' => 25,
            'official music' => 35,
            'copyright' => 35,
            'content id' => 55,
            'vevo' => 45,
            'sony music' => 65,
            'sony' => 25,
            'warner music' => 65,
            'warner' => 25,
            'universal music' => 65,
            'universal' => 25,
            'umg' => 60,
            'wmg' => 60,
            'spotify' => 35,
            'youtube music' => 35,
            'telifli' => 70,
            'orijinal sarki' => 35,
            'full album' => 45,
            'spotify rip' => 85,
            'youtube rip' => 85,
            'cover' => 35,
            'remix' => 30,
            'edit' => 20,
        ];

        $risk = 0;
        $reasons = [];
        foreach ($rules as $needle => $score) {
            if (str_contains($text, $needle)) {
                $risk += $score;
                $reasons[] = 'Riskli ifade: ' . $needle;
            }
        }

        return [
            'risk_score' => min(100, $risk),
            'reasons' => $reasons,
        ];
    }

    public function logResult(array $result): int
    {
        if (empty($result['file_hash']) && empty($result['reasons'])) {
            return 0;
        }

        try {
            $statement = $this->db()->prepare(
                'INSERT INTO music_copyright_checks
                    (track_id, user_id, file_hash, title, artist_name, status, risk_score, reasons, provider, created_at)
                 VALUES
                    (:track_id, :user_id, :file_hash, :title, :artist_name, :status, :risk_score, :reasons, :provider, NOW())'
            );
            $statement->execute([
                'track_id' => $result['track_id'] ?? null,
                'user_id' => $result['user_id'] ?? null,
                'file_hash' => $result['file_hash'] ?? null,
                'title' => $result['title'] ?? '',
                'artist_name' => $result['artist_name'] ?? '',
                'status' => $result['status'] ?? 'pending',
                'risk_score' => (int) ($result['risk_score'] ?? 0),
                'reasons' => json_encode(array_values((array) ($result['reasons'] ?? [])), JSON_UNESCAPED_UNICODE),
                'provider' => $result['provider'] ?? 'local_hash_keyword',
            ]);

            return (int) $this->db()->lastInsertId();
        } catch (Throwable) {
            return 0;
        }
    }

    private function db(): PDO
    {
        if ($this->pdo) {
            return $this->pdo;
        }

        return $this->pdo = Database::connection($this->config ?: null);
    }

    private function absolutePath(string $path): string
    {
        $path = trim($path);
        if ($path === '') {
            return '';
        }

        $base = defined('BASE_PATH') ? BASE_PATH : dirname(__DIR__, 3);
        $normalized = str_replace('\\', '/', $path);

        if (str_starts_with($normalized, '/uploads/') || str_starts_with($normalized, '/assets/')) {
            return $base . '/public' . $normalized;
        }

        if (str_starts_with($normalized, '/public/')) {
            return $base . $normalized;
        }

        if (preg_match('~^[A-Za-z]:/~', $normalized) || str_starts_with($normalized, '/')) {
            return $path;
        }

        return $base . '/' . ltrim($path, '/');
    }

    private function normalize(string $value): string
    {
        $value = strtolower($value);
        $value = strtr($value, [
            'ç' => 'c', 'ğ' => 'g', 'ı' => 'i', 'ö' => 'o', 'ş' => 's', 'ü' => 'u',
            'Ç' => 'c', 'Ğ' => 'g', 'İ' => 'i', 'Ö' => 'o', 'Ş' => 's', 'Ü' => 'u',
        ]);
        $value = preg_replace('~\s+~', ' ', $value) ?: '';

        return trim($value);
    }
}
