<?php

namespace App\Http\Controllers;

use App\Models\Buku;
use Illuminate\Http\Request;

class VisitorKatalogController extends Controller
{
    public function index(Request $request)
    {
        $originalSearch = $request->input('search');

        $bukuPopuler = Buku::withCount('peminjaman')
            ->orderBy('peminjaman_count', 'desc')
            ->take(5)
            ->get();

        if (empty($originalSearch)) {
            $buku = Buku::paginate(12);
            $search = $originalSearch;
            return view('visitor.katalog.index', compact('buku', 'search', 'bukuPopuler'));
        }

        // 1. Text Preprocessing (Stopword Removal)
        // Array stopword bahasa Indonesia sederhana
        $stopwords = ['buku', 'tentang', 'yang', 'di', 'ke', 'dari', 'mencari', 'untuk', 'dan', 'ini', 'itu', 'adalah', 'pada', 'dengan', 'sebuah', 'cara'];

        // Membersihkan input: mengubah ke lowercase dan membuang karakter non-alphanumeric
        $cleanInput = preg_replace('/[^\p{L}\p{N}\s]/u', '', strtolower($originalSearch));
        $words = explode(' ', $cleanInput);

        // Filter stopword
        $filteredWords = array_filter($words, function ($word) use ($stopwords) {
            return !in_array($word, $stopwords) && trim($word) !== '';
        });

        // String hasil preprocessing yang murni siap diproses ke Cosine Similarity
        $processedSearch = implode(' ', $filteredWords);

        if (empty($processedSearch)) {
            // Jika setelah dibersihkan query pencarian menjadi kosong (misal pencarian hanya "buku tentang")
            $buku = new \Illuminate\Pagination\LengthAwarePaginator([], 0, 12, 1, ['path' => $request->url(), 'query' => $request->query()]);
            $search = $originalSearch;
            return view('visitor.katalog.index', compact('buku', 'search', 'bukuPopuler'));
        }

        // 2. Ambil semua buku untuk discoring
        // Karena Cosine Similarity memerlukan pembandingan tiap data terhadap string pencarian
        $semuaBuku = Buku::with('kategori')->get();
        $hasil = [];

        foreach ($semuaBuku as $b) {
            // Hitung nilai Cosine Similarity untuk masing-masing atribut berdasarkan kata kunci yang sudah dibersihkan
            $judulSimilarity = $this->calculateSimilarity($processedSearch, $b->judul);
            $pengarangSimilarity = $this->calculateSimilarity($processedSearch, $b->pengarang);

            // Gabungkan penerbit, deskripsi, dan kategori sebagai atribut teks tambahan
            $teksTambahan = trim(($b->penerbit ?? '') . ' ' . ($b->deskripsi ?? '') . ' ' . ($b->kategori->nama_kategori ?? ''));
            $tambahanSimilarity = $this->calculateSimilarity($processedSearch, $teksTambahan);

            // Penyesuaian Bobot WTS (Weighting)
            // Judul (70%), Pengarang (20%), Penerbit/Deskripsi/Kategori (10%)
            $totalScore = ($judulSimilarity * 0.7) + ($pengarangSimilarity * 0.2) + ($tambahanSimilarity * 0.1);

            // 3. Penetapan Batas Relevansi (Threshold)
            // Hanya tampilkan yang memiliki Total Similarity Score >= 0.3 (30%)
            if ($totalScore >= 0.3) {
                $b->similarity_score = $totalScore;
                $hasil[] = $b;
            }
        }

        // Urutkan berdasarkan similarity_score terbesar (descending)
        usort($hasil, function ($a, $b) {
            return $b->similarity_score <=> $a->similarity_score;
        });

        // 4. Buat manual LengthAwarePaginator untuk memecah hasil dan merender pagination view
        $currentPage = \Illuminate\Pagination\Paginator::resolveCurrentPage();
        $perPage = 12;
        $currentItems = array_slice($hasil, ($currentPage - 1) * $perPage, $perPage);
        $buku = new \Illuminate\Pagination\LengthAwarePaginator($currentItems, count($hasil), $perPage, $currentPage, [
            'path' => $request->url(),
            'query' => $request->query()
        ]);

        $search = $originalSearch; // Kembalikan search asli ke search bar agar tidak membingungkan user
        return view('visitor.katalog.index', compact('buku', 'search', 'bukuPopuler'));
    }

    /**
     * Helper untuk menghitung nilai perbandingan kemiripan teks.
     * Menggunakan pendekatan Cosine Similarity yang dimodifikasi (Query Coverage)
     * agar panjang judul buku tidak menurunkan skor secara drastis
     * pada pencarian kata kunci pendek.
     */
    private function calculateSimilarity($query, $text)
    {
        if (empty(trim($text))) return 0;

        $queryWords = explode(' ', strtolower(preg_replace('/[^\p{L}\p{N}\s]/u', '', $query)));
        $textWords = explode(' ', strtolower(preg_replace('/[^\p{L}\p{N}\s]/u', '', $text)));

        // Frekuensi kata
        $vecA = array_count_values(array_filter($queryWords));
        $vecB = array_count_values(array_filter($textWords));

        $terms = array_unique(array_merge(array_keys($vecA), array_keys($vecB)));

        $dotProduct = 0;
        $normA = 0;
        $normB = 0;

        foreach ($terms as $term) {
            $valA = $vecA[$term] ?? 0;
            $valB = $vecB[$term] ?? 0;

            $dotProduct += ($valA * $valB);
            $normA += pow($valA, 2);
            $normB += pow($valB, 2);
        }

        if ($normA == 0 || $normB == 0) return 0;

        // Standard Cosine Similarity: $dotProduct / (sqrt($normA) * sqrt($normB))
        // Kelemahannya: Jika judul buku sangat panjang (normB besar), skor akan anjlok (misal < 0.2)
        // padahal kata pencariannya cocok 100%.
        // Modifikasi menjadi Query Coverage (Pembagi dominan adalah panjang query).
        return $dotProduct / $normA;
    }

    public function show($id)
    {
        $buku = Buku::with(['kategori', 'peminjaman.user'])->findOrFail($id);
        $lokasi = $this->prediksiLokasiRak($buku->nomor_panggil);
        $rekomendasi = $this->getRekomendasi($buku);

        return view('visitor.katalog.show', compact('buku', 'lokasi', 'rekomendasi'));
    }

    private function getRekomendasi($targetBuku)
    {
        $semuaBuku = Buku::where('id_buku', '!=', $targetBuku->id_buku)
            ->get();

        // Jika nomor_panggil tidak ada, tampilkan rekomendasi berdasarkan buku populer
        if (empty($targetBuku->nomor_panggil)) {
            return $semuaBuku->take(4);
        }

        $hasil = [];
        $targetDdc = substr(preg_replace('/[^0-9]/', '', $targetBuku->nomor_panggil), 0, 3);

        if (strlen($targetDdc) < 3) {
            return collect([]);
        }

        foreach ($semuaBuku as $b) {
            if (empty($b->nomor_panggil)) continue;

            $pembandingDdc = substr(preg_replace('/[^0-9]/', '', $b->nomor_panggil), 0, 3);
            if (strlen($pembandingDdc) < 3) continue;

            $skor = 0;
            if ($targetDdc[0] === $pembandingDdc[0]) {
                $skor += 0.2;
                if ($targetDdc[1] === $pembandingDdc[1]) {
                    $skor += 0.3;
                    if ($targetDdc[2] === $pembandingDdc[2]) {
                        $skor += 0.5;
                    }
                }
            }

            if ($skor > 0) {
                $b->similarity_score = $skor;
                $hasil[] = $b;
            }
        }

        usort($hasil, function ($a, $b) {
            return $b->similarity_score <=> $a->similarity_score;
        });

        return collect(array_slice($hasil, 0, 4));
    }

    private function prediksiLokasiRak($nomor_panggil)
    {
        if (empty($nomor_panggil)) {
            return ['rak' => 'Tidak Diketahui', 'area' => 'Hubungi Petugas', 'kode_rak' => 'none'];
        }

        $kode_utama = (int) substr(trim($nomor_panggil), 0, 3);

        return match (true) {
            $kode_utama >= 0 && $kode_utama <= 99 => match (true) {
                $kode_utama <= 19 => ['rak' => 'Rak 01', 'area' => 'Karya Umum (Bibliografi)', 'kode_rak' => 'rak_000'],
                $kode_utama <= 50 => ['rak' => 'Rak 02', 'area' => 'Karya Umum (Ensiklopedia)', 'kode_rak' => 'rak_000'],
                default => ['rak' => 'Rak 03-05', 'area' => 'Karya Umum Lainnya', 'kode_rak' => 'rak_000'],
            },

            $kode_utama >= 100 && $kode_utama <= 199 => match (true) {
                $kode_utama <= 150 => ['rak' => 'Rak 06-10', 'area' => 'Filsafat', 'kode_rak' => 'rak_100'],
                default => ['rak' => 'Rak 11-14', 'area' => 'Psikologi', 'kode_rak' => 'rak_100'],
            },

            $kode_utama >= 200 && $kode_utama <= 299 => match (true) {
                $kode_utama == 297 => ['rak' => 'Rak 25-32', 'area' => 'Agama Islam', 'kode_rak' => 'rak_200'],
                default => ['rak' => 'Rak 15-24', 'area' => 'Agama Umum & Lainnya', 'kode_rak' => 'rak_200'],
            },

            $kode_utama >= 300 && $kode_utama <= 399 => match (true) {
                $kode_utama <= 330 => ['rak' => 'Rak 33-36', 'area' => 'Sosiologi & Ilmu Politik', 'kode_rak' => 'rak_300'],
                $kode_utama <= 360 => ['rak' => 'Rak 37-40', 'area' => 'Ekonomi & Hukum', 'kode_rak' => 'rak_300'],
                default => ['rak' => 'Rak 41-44', 'area' => 'Pendidikan & Adat', 'kode_rak' => 'rak_300'],
            },

            $kode_utama >= 400 && $kode_utama <= 499 => ['rak' => 'Rak 45', 'area' => 'Bahasa', 'kode_rak' => 'rak_400'],

            $kode_utama >= 500 && $kode_utama <= 599 => ['rak' => 'Rak 46-48', 'area' => 'Ilmu Murni', 'kode_rak' => 'rak_500'],

            $kode_utama >= 600 && $kode_utama <= 699 => match (true) {
                $kode_utama <= 610 => ['rak' => 'Rak 49-53', 'area' => 'Ilmu Kedokteran', 'kode_rak' => 'rak_600'],
                $kode_utama <= 630 => ['rak' => 'Rak 54-58', 'area' => 'Ilmu Teknik', 'kode_rak' => 'rak_600'],
                $kode_utama <= 650 => ['rak' => 'Rak 59-63', 'area' => 'Pertanian', 'kode_rak' => 'rak_600'],
                default => ['rak' => 'Rak 64-68', 'area' => 'Manajemen & Bisnis', 'kode_rak' => 'rak_600'],
            },

            $kode_utama >= 700 && $kode_utama <= 799 => match (true) {
                $kode_utama <= 739 => ['rak' => 'Rak 71', 'area' => 'Kesenian Murni', 'kode_rak' => 'rak_700'],
                $kode_utama <= 769 => ['rak' => 'Rak 72', 'area' => 'Seni Rupa & Kriya', 'kode_rak' => 'rak_700'],
                $kode_utama <= 789 => ['rak' => 'Rak 73', 'area' => 'Fotografi & Musik', 'kode_rak' => 'rak_700'],
                default => ['rak' => 'Rak 74', 'area' => 'Olahraga & Hiburan', 'kode_rak' => 'rak_700'],
            },

            $kode_utama >= 800 && $kode_utama <= 899 => ['rak' => 'Rak 77-79', 'area' => 'Kesusastraan (Sastra)', 'kode_rak' => 'rak_800'],

            $kode_utama >= 900 && $kode_utama <= 999 => match (true) {
                $kode_utama <= 919 => ['rak' => 'Rak 69, 70', 'area' => 'Geografi & Perjalanan', 'kode_rak' => 'rak_900'],
                default => ['rak' => 'Rak 80-84', 'area' => 'Sejarah Umum', 'kode_rak' => 'rak_900'],
            },

            default => ['rak' => 'Rak 75-76', 'area' => 'Koleksi Terbaru', 'kode_rak' => 'rak_baru'],
        };
    }
}
