<?php

namespace App\Models;

use CodeIgniter\Model;

class DocumentModel extends Model
{
    protected $table         = 'documents';
    protected $primaryKey    = 'id';
    protected $returnType    = 'array';
    protected $useTimestamps = true;
    protected $allowedFields = [
        'title', 'author_name', 'author_user_id', 'nim', 'study_program_id',
        'document_type_id', 'year', 'abstract', 'keywords', 'supervisor',
        'publisher', 'cover_img', 'file_path', 'status', 'admin_note',
        'citations_count', 'view_count', 'download_count',
        'submitted_at', 'reviewed_at', 'published_at',
    ];

    public function getWithMeta(int $id): ?array
    {
        return $this->db->table('documents d')
            ->select('d.*, dt.name AS type_name, dt.slug AS type_slug, sp.name AS program_name')
            ->join('document_types dt', 'dt.id = d.document_type_id')
            ->join('study_programs sp', 'sp.id = d.study_program_id', 'left')
            ->where('d.id', $id)
            ->get()->getRowArray();
    }

    public function getPublished(array $filters = [], int $perPage = 12): array
    {
        $builder = $this->db->table('documents d')
            ->select('d.*, dt.name AS type_name, dt.slug AS type_slug, sp.name AS program_name')
            ->join('document_types dt', 'dt.id = d.document_type_id')
            ->join('study_programs sp', 'sp.id = d.study_program_id', 'left')
            ->where('d.status', 'published');

        $this->applyFilters($builder, $filters);

        $total   = $builder->countAllResults(false);
        $page    = (int) ($filters['page'] ?? 1);
        $offset  = ($page - 1) * $perPage;
        $results = $builder->limit($perPage, $offset)->get()->getResultArray();

        return ['data' => $results, 'total' => $total, 'perPage' => $perPage, 'page' => $page];
    }

    public function getAllAdmin(array $filters = [], int $perPage = 20): array
    {
        $builder = $this->db->table('documents d')
            ->select('d.*, dt.name AS type_name, sp.name AS program_name, up.name AS submitter_name')
            ->join('document_types dt', 'dt.id = d.document_type_id')
            ->join('study_programs sp', 'sp.id = d.study_program_id', 'left')
            ->join('user_profiles up', 'up.user_id = d.author_user_id', 'left');

        if (!empty($filters['status'])) {
            $builder->where('d.status', $filters['status']);
        }
        $this->applyFilters($builder, $filters);

        $total   = $builder->countAllResults(false);
        $page    = (int) ($filters['page'] ?? 1);
        $offset  = ($page - 1) * $perPage;
        $results = $builder->orderBy('d.updated_at', 'DESC')->limit($perPage, $offset)->get()->getResultArray();

        return ['data' => $results, 'total' => $total, 'perPage' => $perPage, 'page' => $page];
    }

    public function getByAuthor(int $user_id, array $filters = []): array
    {
        $builder = $this->db->table('documents d')
            ->select('d.*, dt.name AS type_name, sp.name AS program_name')
            ->join('document_types dt', 'dt.id = d.document_type_id')
            ->join('study_programs sp', 'sp.id = d.study_program_id', 'left')
            ->where('d.author_user_id', $user_id);

        if (!empty($filters['status'])) {
            $builder->where('d.status', $filters['status']);
        }

        return $builder->orderBy('d.updated_at', 'DESC')->get()->getResultArray();
    }

    public function searchPublished(string $query): array
    {
        return $this->db->table('documents d')
            ->select('d.id, d.title, d.author_name, d.year, dt.name AS type_name')
            ->join('document_types dt', 'dt.id = d.document_type_id')
            ->where('d.status', 'published')
            ->groupStart()
                ->like('d.title', $query)
                ->orLike('d.author_name', $query)
                ->orLike('d.keywords', $query)
            ->groupEnd()
            ->limit(10)
            ->get()->getResultArray();
    }

    public function incrementView(int $id): void
    {
        $this->db->query('UPDATE documents SET view_count = view_count + 1 WHERE id = ?', [$id]);
    }

    public function incrementDownload(int $id): void
    {
        $this->db->query('UPDATE documents SET download_count = download_count + 1 WHERE id = ?', [$id]);
    }

    public function incrementCitations(int $id): void
    {
        $this->db->query('UPDATE documents SET citations_count = citations_count + 1 WHERE id = ?', [$id]);
    }

    public function decrementCitations(int $id): void
    {
        $this->db->query('UPDATE documents SET citations_count = GREATEST(citations_count - 1, 0) WHERE id = ?', [$id]);
    }

    public function getTopCited(int $limit = 5): array
    {
        return $this->where('status', 'published')
            ->orderBy('citations_count', 'DESC')
            ->orderBy('view_count', 'DESC')
            ->limit($limit)
            ->findAll();
    }

    public function getStats(): array
    {
        $total     = $this->countAll();
        $published = $this->where('status', 'published')->countAllResults();
        $pending   = $this->whereIn('status', ['submitted', 'review'])->countAllResults();
        $draft     = $this->where('status', 'draft')->countAllResults();

        return compact('total', 'published', 'pending', 'draft');
    }

    private function applyFilters($builder, array $filters): void
    {
        if (!empty($filters['type'])) {
            $builder->where('d.document_type_id', $filters['type']);
        }
        if (!empty($filters['program'])) {
            $builder->where('d.study_program_id', $filters['program']);
        }
        if (!empty($filters['year'])) {
            $builder->where('d.year', $filters['year']);
        }
        if (!empty($filters['search'])) {
            $builder->groupStart()
                ->like('d.title', $filters['search'])
                ->orLike('d.author_name', $filters['search'])
                ->orLike('d.abstract', $filters['search'])
                ->orLike('d.keywords', $filters['search'])
                ->groupEnd();
        }

        $sort = $filters['sort'] ?? 'latest';
        match ($sort) {
            'cited'    => $builder->orderBy('d.citations_count', 'DESC'),
            'popular'  => $builder->orderBy('d.view_count', 'DESC'),
            'az'       => $builder->orderBy('d.title', 'ASC'),
            default    => $builder->orderBy('d.published_at', 'DESC')->orderBy('d.created_at', 'DESC'),
        };
    }
}
