<?php

namespace App\Services\Admin\Users;

use App\Models\Student;
use App\Models\User;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;

class StudentService
{
    public function getAllForSelect(?string $status = null): Collection
    {
        return Student::select(['id', 'user_id', 'student_number', 'department_id', 'current_semester'])
            ->with([
                'user:id,username',
                'user.profile:id,user_id,full_name',
                'department:id,name',
            ])
            ->when($status, fn ($q) => $q->where('status', $status))
            ->get();
    }

    public function getEnrollmentYears(): array
    {
        return Student::query()
            ->select('enrollment_year')
            ->distinct()
            ->orderByDesc('enrollment_year')
            ->pluck('enrollment_year')
            ->all();
    }

    public function paginated(int $perPage = 25, string $search = '', ?string $gender = null, ?int $departmentId = null, ?string $status = null, ?int $enrollmentYear = null): LengthAwarePaginator
    {
        return $this->filteredQuery($search, $gender, $departmentId, $status, $enrollmentYear)
            ->latest()
            ->paginate($perPage);
    }

    public function forExport(string $search = '', ?string $gender = null, ?int $departmentId = null, ?string $status = null, ?int $enrollmentYear = null): Collection
    {
        return $this->filteredQuery($search, $gender, $departmentId, $status, $enrollmentYear)
            ->orderBy('created_at', 'desc')
            ->get();
    }

    private function filteredQuery(string $search, ?string $gender, ?int $departmentId, ?string $status, ?int $enrollmentYear = null): Builder
    {
        return User::select(['id', 'username', 'email', 'is_active'])
            ->with([
                'profile:id,user_id,full_name,phone_number,gender,birth_place,birth_date,address',
                'student:id,user_id,student_number,department_id,enrollment_year,current_semester,status',
                'student.department:id,name',
            ])
            ->whereHas('roles', fn ($q) => $q->where('name', 'mahasiswa'))
            ->when($search, fn ($q) => $q->where(function ($query) use ($search) {
                $query->where('username', 'like', "%{$search}%")
                    ->orWhere('email', 'like', "%{$search}%")
                    ->orWhereHas('profile', fn ($q) => $q->where('full_name', 'like', "%{$search}%"))
                    ->orWhereHas('student', fn ($q) => $q->where('student_number', 'like', "%{$search}%"));
            }))
            ->when($gender, fn ($q) => $q->whereHas('profile', fn ($q) => $q->where('gender', $gender)))
            ->when($departmentId, fn ($q) => $q->whereHas('student', fn ($q) => $q->where('department_id', $departmentId)))
            ->when($status, fn ($q) => $q->whereHas('student', fn ($q) => $q->where('status', $status)))
            ->when($enrollmentYear, fn ($q) => $q->whereHas('student', fn ($q) => $q->where('enrollment_year', $enrollmentYear)));
    }

    public function create(array $data): User
    {
        return DB::transaction(function () use ($data) {
            $user = User::create([
                'username' => $data['username'],
                'email' => $data['email'],
                'password' => Hash::make(config('app.default_password')),
            ]);

            $user->assignRole('mahasiswa');

            $user->profile()->create([
                'full_name' => $data['full_name'],
                'phone_number' => $data['phone_number'],
                'address' => $data['address'],
                'gender' => $data['gender'],
                'birth_date' => $data['birth_date'],
                'birth_place' => $data['birth_place'],
            ]);

            $user->student()->create([
                'student_number' => $data['student_number'],
                'department_id' => $data['department_id'],
                'enrollment_year' => $data['enrollment_year'],
                'current_semester' => $data['current_semester'],
                'academic_advisor_id' => $data['academic_advisor_id'],
                'status' => 'active',
            ]);

            return $user;
        });
    }

    public function update(User $user, array $data): User
    {
        DB::transaction(function () use ($user, $data) {
            $user->update([
                'username' => $data['username'],
                'email' => $data['email'],
            ]);

            $user->profile()->updateOrCreate([], [
                'full_name' => $data['full_name'],
                'phone_number' => $data['phone_number'],
                'address' => $data['address'],
                'gender' => $data['gender'],
                'birth_date' => $data['birth_date'],
                'birth_place' => $data['birth_place'],
            ]);

            $user->student()->updateOrCreate([], [
                'student_number' => $data['student_number'],
                'department_id' => $data['department_id'],
                'enrollment_year' => $data['enrollment_year'],
                'current_semester' => $data['current_semester'],
                'academic_advisor_id' => $data['academic_advisor_id'],
            ]);
        });

        return $user->fresh(['profile', 'student.department', 'roles']);
    }

    public function delete(User $user): void
    {
        DB::transaction(function () use ($user) {
            $user->student()->delete();
            $user->profile()->delete();
            $user->delete();
        });
    }

    public function resetPassword(User $user): void
    {
        $user->update([
            'password' => Hash::make(config('app.default_password')),
        ]);
    }

    public function updateStatus(User $user, string $status): void
    {
        $user->student()->update(['status' => $status]);
    }

    public function updateUserStatus(User $user, bool $isActive): void
    {
        $user->update(['is_active' => $isActive]);
    }
}
