<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use App\Models\BaseModel;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Facades\DB;

class UserRole extends BaseModel
{
    use SoftDeletes;

    protected $table = 'user_roles';

    protected $fillable = [
        'user_id',
        'role_id',
        'created_at',
        'updated_at',
        'deleted_at',
        'updated_by',
    ];

    protected $casts = [
        'user_id'     => 'integer',
        'role_id'     => 'integer',
        'updated_by'  => 'integer',
        'created_at'  => 'datetime',
        'updated_at'  => 'datetime',
        'deleted_at'  => 'datetime',
    ];

    /* ============================================================
     * Relationships
     * ============================================================
     */

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    public function role(): BelongsTo
    {
        return $this->belongsTo(Role::class, 'role_id');
    }

    /* ============================================================
     * Scopes
     * ============================================================
     */

    public function scopeForUser(Builder $q, int $userId): Builder
    {
        return $q->where('user_id', $userId);
    }

    public function scopeForRole(Builder $q, int $roleId): Builder
    {
        return $q->where('role_id', $roleId);
    }

    public function scopeForSchoolYear(Builder $q, ?string $schoolYear): Builder
    {
        if ($schoolYear === null || trim($schoolYear) === '') return $q;
        return $q->where('school_year', $schoolYear);
    }

    /* ============================================================
     * CI-compatible methods (converted)
     * ============================================================
     */

    /**
     * CI: getRolesByUserId($userId)
     * Returns: [ ['role_name' => 'parent'], ['role_name' => 'teacher'] ]
     */
    public static function getRolesByUserId(int $userId): array
    {
        return static::query()
            ->selectRaw('roles.name as role_name')
            ->join('roles', 'roles.id', '=', 'user_roles.role_id')
            ->where('user_roles.user_id', $userId)
            ->whereNull('user_roles.deleted_at')
            ->orderBy('roles.priority', 'asc')
            ->orderBy('roles.name', 'asc')
            ->get()
            ->map(fn ($r) => ['role_name' => (string) $r->role_name])
            ->all();
    }

    /**
     * CI: updateOrInsertRole($userId, $roleId)
     * Idempotent (does nothing if already exists and not soft-deleted).
     * If the row exists but is soft-deleted, restores it.
     */
    public static function updateOrInsertRole(int $userId, int $roleId, ?int $editorId = null): bool
    {
        $editorId = $editorId ?? (auth()->id() ?? null);

        $existing = static::withTrashed()
            ->where('user_id', $userId)
            ->where('role_id', $roleId)
            ->first();

        if ($existing) {
            if ($existing->trashed()) {
                $existing->restore();
            }
            // keep updated_by fresh
            if ($editorId !== null) {
                $existing->updated_by = $editorId;
                $existing->save();
            }
            return true;
        }

        static::query()->create([
            'user_id'    => $userId,
            'role_id'    => $roleId,
            'updated_by' => $editorId,
        ]);

        return true;
    }

    /* ============================================================
     * Replacement for the CI "create()" method (query only)
     * ============================================================
     * In Laravel, view rendering belongs in Controllers, not Models.
     * This returns the user list that your CI method was building.
     *
     * CI logic:
     * users joined to roles through user_roles, excluding parent/teacher,
     * groupBy users.id to avoid duplicates.
     */
    public static function usersExcludingRoles(array $excludedRoleNames = ['parent', 'teacher']): array
    {
        $excluded = array_values(array_unique(array_filter(array_map('strval', $excludedRoleNames))));
        $excludedLower = array_map('strtolower', $excluded);

        $placeholders = implode(',', array_fill(0, count($excludedLower), '?'));

        return DB::table('users')
            ->select('users.*')
            ->join('user_roles', 'user_roles.user_id', '=', 'users.id')
            ->join('roles', 'roles.id', '=', 'user_roles.role_id')
            ->whereNull('user_roles.deleted_at')
            ->whereRaw("LOWER(roles.name) NOT IN ($placeholders)", $excludedLower)
            ->groupBy('users.id')
            ->orderBy('users.lastname', 'asc')
            ->orderBy('users.firstname', 'asc')
            ->get()
            ->map(fn ($r) => (array) $r)
            ->all();
    }

    /* ============================================================
     * Optional validation helper
     * ============================================================
     */
    public static function rules(bool $updating = false): array
    {
        $req = $updating ? 'sometimes' : 'required';

        return [
            'user_id'    => [$req, 'integer', 'min:1', 'exists:users,id'],
            'role_id'    => [$req, 'integer', 'min:1', 'exists:roles,id'],
            'semester'   => ['nullable', 'string', 'max:20'],
            'school_year'=> ['nullable', 'string', 'max:20'],
            'updated_by' => ['nullable', 'integer'],
        ];
    }
}