<?php

namespace App\Models;

use App\Entities\Job;
use CodeIgniter\Model;

class JobModel extends Model
{
    protected $table          = 'jobs';
    protected $primaryKey     = 'id';
    protected $returnType     = Job::class;
    protected $useSoftDeletes = true;
    protected $useTimestamps  = true;
    protected $allowedFields  = [
        'agency_id', 'posted_by_user_id', 'title', 'description', 'department',
        'category_id', 'experience_level', 'salary_min', 'salary_max', 'salary_currency',
        'is_salary_visible', 'location', 'city', 'country', 'is_remote', 'is_hybrid',
        'is_visa_sponsorship', 'is_fresh_graduate_ok', 'is_easy_apply', 'required_skills',
        'employment_type', 'education_requirement', 'benefits', 'status', 'is_featured',
        'is_urgent', 'views_count', 'expires_at', 'seo_slug', 'meta_title', 'meta_description',
    ];

    protected $validationRules = [
        'title'       => 'required|max_length[200]',
        'description' => 'required|min_length[50]',
        'seo_slug'    => 'required|is_unique[jobs.seo_slug,id,{id}]',
    ];

    public function findBySlug(string $slug): ?Job
    {
        return $this->where('seo_slug', $slug)->first();
    }

    /**
     * Public job search — deliberately NOT tenant-scoped (candidates browse
     * across all agencies). Only 'published' + non-expired jobs are ever
     * eligible here.
     */
    public function searchPublic(array $filters, int $page = 1, int $perPage = 20): array
    {
        $builder = $this->select('jobs.*, agencies.company_name, agencies.logo_path, agencies.verification_status, owner.username as agency_username,
                (SELECT COUNT(*) FROM job_applications WHERE job_applications.job_id = jobs.id) as applicant_count')
            ->join('agencies', 'agencies.id = jobs.agency_id')
            ->join('users as owner', 'owner.id = agencies.owner_user_id')
            ->where('jobs.status', 'published')
            ->groupStart()
                ->where('jobs.expires_at >=', date('Y-m-d'))
                ->orWhere('jobs.expires_at', null)
            ->groupEnd();

        if (! empty($filters['company_name'])) {
            $builder->like('agencies.company_name', $filters['company_name']);
        }
        if (! empty($filters['industry'])) {
            $builder->where('agencies.industry', $filters['industry']);
        }

        // Keyword Search — across title + description (full-text indexed).
        if (! empty($filters['q'])) {
            $builder->groupStart()
                ->like('jobs.title', $filters['q'])
                ->orLike('jobs.description', $filters['q'])
            ->groupEnd();
        }
        // Job Title — a more targeted filter than the general keyword search.
        if (! empty($filters['job_title'])) {
            $builder->like('jobs.title', $filters['job_title']);
        }
        if (! empty($filters['department'])) {
            $builder->like('jobs.department', $filters['department']);
        }
        if (! empty($filters['skills'])) {
            $skills = is_array($filters['skills']) ? $filters['skills'] : explode(',', $filters['skills']);
            foreach ($skills as $skill) {
                $builder->like('jobs.required_skills', trim($skill));
            }
        }
        if (! empty($filters['category_id'])) {
            $builder->where('jobs.category_id', $filters['category_id']);
        }

        // Experience Level / Career Level — the spec lists these as two
        // separate filters, but this schema has one enum
        // (experience_level) serving both concepts; both filter params map
        // to the same column so either name works from the client side.
        $level = $filters['experience_level'] ?? $filters['career_level'] ?? null;
        if (! empty($level)) {
            $builder->where('jobs.experience_level', $level);
        }

        if (! empty($filters['education_level'])) {
            $builder->like('jobs.education_requirement', $filters['education_level']);
        }

        // Location / City / Country
        if (! empty($filters['location'])) {
            $builder->like('jobs.location', $filters['location']);
        }
        if (! empty($filters['city'])) {
            $builder->where('jobs.city', $filters['city']);
        }
        if (! empty($filters['country'])) {
            $builder->where('jobs.country', $filters['country']);
        }

        // Remote / Hybrid / Onsite — "onsite" means neither flag is set.
        if (! empty($filters['work_mode'])) {
            match ($filters['work_mode']) {
                'remote' => $builder->where('jobs.is_remote', 1),
                'hybrid' => $builder->where('jobs.is_hybrid', 1),
                'onsite' => $builder->where('jobs.is_remote', 0)->where('jobs.is_hybrid', 0),
                default  => null,
            };
        }

        // Employment Type — accepts either one value or an array/CSV of
        // several (e.g. "Full Time" + "Contract" both checked).
        if (! empty($filters['employment_type'])) {
            $types = is_array($filters['employment_type']) ? $filters['employment_type'] : explode(',', $filters['employment_type']);
            $builder->whereIn('jobs.employment_type', $types);
        }

        // Salary Range
        if (! empty($filters['salary_min'])) {
            $builder->where('jobs.salary_max >=', $filters['salary_min']);
        }
        if (! empty($filters['salary_max'])) {
            $builder->where('jobs.salary_min <=', $filters['salary_max']);
        }

        // Posted Date Ranges
        if (! empty($filters['posted_within'])) {
            $since = match ($filters['posted_within']) {
                'today'      => date('Y-m-d 00:00:00'),
                'this_week'  => date('Y-m-d 00:00:00', strtotime('monday this week')),
                'this_month' => date('Y-m-01 00:00:00'),
                default      => null,
            };
            if ($since) {
                $builder->where('jobs.created_at >=', $since);
            }
        }

        // Boolean toggles
        if (! empty($filters['is_urgent'])) {
            $builder->where('jobs.is_urgent', 1);
        }
        if (! empty($filters['is_easy_apply'])) {
            $builder->where('jobs.is_easy_apply', 1);
        }
        if (! empty($filters['is_visa_sponsorship'])) {
            $builder->where('jobs.is_visa_sponsorship', 1);
        }
        if (! empty($filters['is_fresh_graduate_ok'])) {
            $builder->where('jobs.is_fresh_graduate_ok', 1);
        }

        $offset = ($page - 1) * $perPage;

        return $builder->orderBy('jobs.is_featured', 'DESC')
            ->orderBy('jobs.is_urgent', 'DESC')
            ->orderBy('jobs.created_at', 'DESC')
            ->findAll($perPage, $offset);
    }

    public function incrementViews(int $jobId): void
    {
        $this->set('views_count', 'views_count + 1', false)->where('id', $jobId)->update();
    }
}
