<?php

use App\Models\User;
use App\Models\DataDesa;
use App\Models\Penduduk;
use App\Models\Keluarga;
use App\Models\Profil;
use App\Models\SettingAplikasi;
use App\Models\OtpToken;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Carbon;



// User Model Scopes
it('can filter users by role', function () {
    $adminRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'admin']);
    $userRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'user']);

    $adminUser = User::factory()->create();
    $regularUser = User::factory()->create();

    $adminUser->assignRole($adminRole);
    $regularUser->assignRole($userRole);

    $adminUsers = User::role('admin')->get();
    $regularUsers = User::role('user')->get();

    expect($adminUsers->count())->toBeGreaterThanOrEqual(1);
    expect($adminUsers->first()->id)->toBe($adminUser->id);
    expect($regularUsers->count())->toBeGreaterThanOrEqual(1);
    expect($regularUsers->first()->id)->toBe($regularUser->id);
});

it('can filter users by permission', function () {
    $permission = \Spatie\Permission\Models\Permission::firstOrCreate(['name' => 'edit-users']);
    $role = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'admin']);
    $role->givePermissionTo($permission);

    $adminUser = User::factory()->create();
    $regularUser = User::factory()->create();

    $adminUser->assignRole($role);

    $usersWithPermission = User::permission('edit-users')->get();

    expect($usersWithPermission->count())->toBeGreaterThanOrEqual(1);
    expect($usersWithPermission->first()->id)->toBe($adminUser->id);
});

// Penduduk Model Scopes
it('can filter penduduk by hidup scope', function () {
    $livingPenduduk = Penduduk::factory()->create(['status_dasar' => 1]); // Assuming 1 is alive
    $deadPenduduk = Penduduk::factory()->create(['status_dasar' => 0]); // Assuming 0 is dead

    $livingPendudukList = Penduduk::hidup()->get();

    expect($livingPendudukList->count())->toBeGreaterThanOrEqual(1);
    expect($livingPendudukList->pluck('id'))->toContain($livingPenduduk->id);
});

it('can filter penduduk by sex', function () {
    $malePenduduk = Penduduk::factory()->create(['sex' => 1]); // Assuming 1 is male
    $femalePenduduk = Penduduk::factory()->create(['sex' => 2]); // Assuming 2 is female

    $malePendudukList = Penduduk::where('sex', 1)->get();
    $femalePendudukList = Penduduk::where('sex', 2)->get();

    expect($malePendudukList->count())->toBeGreaterThanOrEqual(1);
    expect($malePendudukList->pluck('id'))->toContain($malePenduduk->id);
    expect($femalePendudukList->count())->toBeGreaterThanOrEqual(1);
    expect($femalePendudukList->pluck('id'))->toContain($femalePenduduk->id);
});

it('can filter penduduk by age range', function () {
    $currentYear = date('Y');
    $childYear = $currentYear - 5;
    $adultYear = $currentYear - 25;
    $elderlyYear = $currentYear - 70;

    $childPenduduk = Penduduk::factory()->create(['tanggal_lahir' => "$childYear-01-01"]);
    $adultPenduduk = Penduduk::factory()->create(['tanggal_lahir' => "$adultYear-01-01"]);
    $elderlyPenduduk = Penduduk::factory()->create(['tanggal_lahir' => "$elderlyYear-01-01"]);

    // Test age-based filtering if scope exists
    $childrenYear = $currentYear - 17;
    $seniorYear = $currentYear - 60;

    $children = Penduduk::where('tanggal_lahir', '>', "$childrenYear-12-31")->get();
    $adults = Penduduk::where('tanggal_lahir', '<=', "$childrenYear-12-31")
        ->where('tanggal_lahir', '>', "$seniorYear-12-31")->get();
    $elderly = Penduduk::where('tanggal_lahir', '<=', "$seniorYear-12-31")->get();

    expect($children->count())->toBeGreaterThanOrEqual(1);
    expect($children->pluck('id'))->toContain($childPenduduk->id);
    expect($adults->count())->toBeGreaterThanOrEqual(1);
    expect($adults->pluck('id'))->toContain($adultPenduduk->id);
    expect($elderly->count())->toBeGreaterThanOrEqual(1);
    expect($elderly->pluck('id'))->toContain($elderlyPenduduk->id);
});

// Keluarga Model Scopes
it('can filter keluarga by dusun', function () {
    $dataDesa = DataDesa::factory()->create();
    $keluargaDusun1 = Keluarga::factory()->create([
        'desa_id' => $dataDesa->desa_id,
        'dusun' => 'Dusun 1'
    ]);
    $keluargaDusun2 = Keluarga::factory()->create([
        'desa_id' => $dataDesa->desa_id,
        'dusun' => 'Dusun 2'
    ]);

    $keluargaFromDusun1 = Keluarga::where('dusun', 'Dusun 1')->get();

    expect($keluargaFromDusun1->count())->toBeGreaterThanOrEqual(1);
    expect($keluargaFromDusun1->first()->id)->toBe($keluargaDusun1->id);
});

it('can filter keluarga by RT and RW', function () {
    $dataDesa = DataDesa::factory()->create();
    $keluargaRT1 = Keluarga::factory()->create([
        'desa_id' => $dataDesa->desa_id,
        'rt' => '001',
        'rw' => '001'
    ]);
    $keluargaRT2 = Keluarga::factory()->create([
        'desa_id' => $dataDesa->desa_id,
        'rt' => '002',
        'rw' => '001'
    ]);

    $keluargaFromRT1 = Keluarga::where('rt', '001')->get();
    $keluargaFromRW1 = Keluarga::where('rw', '001')->get();

    expect($keluargaFromRT1->count())->toBeGreaterThanOrEqual(1);
    expect($keluargaFromRT1->pluck('id'))->toContain($keluargaRT1->id);
    expect($keluargaFromRW1->count())->toBeGreaterThanOrEqual(2);
});

// SettingAplikasi Model Scopes
it('can filter settings by category', function () {
    $setting1 = SettingAplikasi::factory()->create(['kategori' => 'aplikasi']);
    $setting2 = SettingAplikasi::factory()->create(['kategori' => 'desa']);
    $setting3 = SettingAplikasi::factory()->create(['kategori' => 'aplikasi']);

    $aplikasiSettings = SettingAplikasi::where('kategori', 'aplikasi')->get();
    $desaSettings = SettingAplikasi::where('kategori', 'desa')->get();

    expect($aplikasiSettings->count())->toBeGreaterThanOrEqual(2);
    expect($desaSettings->count())->toBeGreaterThanOrEqual(1);
    expect($desaSettings->first()->id)->toBe($setting2->id);
});

it('can filter settings by type', function () {
    $textSetting = SettingAplikasi::factory()->create(['type' => 'input']);
    $selectSetting = SettingAplikasi::factory()->create(['type' => 'select']);
    $booleanSetting = SettingAplikasi::factory()->create(['type' => 'textarea']);

    $textSettings = SettingAplikasi::where('type', 'input')->get();
    $selectSettings = SettingAplikasi::where('type', 'select')->get();
    $textareaSettings = SettingAplikasi::where('type', 'textarea')->get();

    expect($textSettings->count())->toBeGreaterThanOrEqual(1);
    expect($selectSettings->count())->toBeGreaterThanOrEqual(1);
    expect($textareaSettings->count())->toBeGreaterThanOrEqual(1);
});

// OtpToken Model Scopes
it('can filter OTP tokens by user', function () {
    $user1 = User::factory()->create();
    $user2 = User::factory()->create();

    $otpToken1 = OtpToken::factory()->create(['user_id' => $user1->id]);
    $otpToken2 = OtpToken::factory()->create(['user_id' => $user1->id]);
    $otpToken3 = OtpToken::factory()->create(['user_id' => $user2->id]);

    $user1Tokens = OtpToken::where('user_id', $user1->id)->get();
    $user2Tokens = OtpToken::where('user_id', $user2->id)->get();

    expect($user1Tokens->count())->toBeGreaterThanOrEqual(2);
    expect($user2Tokens->count())->toBeGreaterThanOrEqual(1);
    expect($user2Tokens->first()->id)->toBe($otpToken3->id);
});

it('can filter OTP tokens by purpose', function () {
    $user = User::factory()->create();

    $loginToken = OtpToken::factory()->create([
        'user_id' => $user->id,
        'purpose' => 'login'
    ]);
    $activationToken = OtpToken::factory()->create([
        'user_id' => $user->id,
        'purpose' => 'activation'
    ]);
    $twoFactorToken = OtpToken::factory()->create([
        'user_id' => $user->id,
        'purpose' => '2fa_login'
    ]);

    $loginTokens = OtpToken::where('purpose', 'login')->get();
    $activationTokens = OtpToken::where('purpose', 'activation')->get();
    $twoFactorTokens = OtpToken::where('purpose', '2fa_login')->get();

    expect($loginTokens->count())->toBeGreaterThanOrEqual(1);
    expect($activationTokens->count())->toBeGreaterThanOrEqual(1);
    expect($twoFactorTokens->count())->toBeGreaterThanOrEqual(1);
});

it('can filter OTP tokens by channel', function () {
    $user = User::factory()->create();

    $emailToken = OtpToken::factory()->create([
        'user_id' => $user->id,
        'channel' => 'email'
    ]);
    $telegramToken = OtpToken::factory()->create([
        'user_id' => $user->id,
        'channel' => 'telegram'
    ]);

    $emailTokens = OtpToken::where('channel', 'email')->get();
    $telegramTokens = OtpToken::where('channel', 'telegram')->get();

    expect($emailTokens->count())->toBeGreaterThanOrEqual(1);
    expect($telegramTokens->count())->toBeGreaterThanOrEqual(1);
});

// Complex Scope Testing
it('can combine multiple scopes', function () {
    $dataDesa = DataDesa::factory()->create();
    $keluarga = Keluarga::factory()->create([
        'desa_id' => $dataDesa->desa_id,
        'dusun' => 'Dusun 1',
        'rt' => '001',
        'rw' => '001'
    ]);

    $malePenduduk = Penduduk::factory()->create([
        'desa_id' => $dataDesa->desa_id,
        'no_kk' => $keluarga->no_kk,
        'sex' => 1, // Male
        'status_dasar' => 1 // Alive
    ]);

    $femalePenduduk = Penduduk::factory()->create([
        'desa_id' => $dataDesa->desa_id,
        'no_kk' => $keluarga->no_kk,
        'sex' => 2, // Female
        'status_dasar' => 1 // Alive
    ]);

    $deadPenduduk = Penduduk::factory()->create([
        'desa_id' => $dataDesa->desa_id,
        'no_kk' => $keluarga->no_kk,
        'sex' => 1, // Male
        'status_dasar' => 0 // Dead
    ]);

    // Combine scopes: living males from Dusun 1
    $livingMalesFromDusun1 = Penduduk::where('status_dasar', 1)
        ->where('sex', 1)
        ->whereHas('keluarga', function ($query) {
            $query->where('dusun', 'Dusun 1');
        })->get();

    expect($livingMalesFromDusun1->count())->toBeGreaterThanOrEqual(1);
    expect($livingMalesFromDusun1->first()->id)->toBe($malePenduduk->id);
});

// Mutator Testing
it('can mutate attributes before saving', function () {
    $penduduk = Penduduk::factory()->make();

    // Test if name mutator exists (e.g., to capitalize)
    $penduduk->nama = 'john doe';
    $penduduk->save();

    // Check if the name was properly formatted
    $savedPenduduk = Penduduk::find($penduduk->id);

    // This test depends on the actual implementation of mutators
    // Adjust based on actual model behavior
    expect($savedPenduduk->nama)->toBeString();
});

it('can mutate NIK before saving', function () {
    $penduduk = Penduduk::factory()->make();

    // Test if NIK mutator exists (e.g., to remove spaces)
    $penduduk->nik = '1234567890123456'; // Use valid 16-digit NIK without spaces
    $penduduk->save();

    // Check if the NIK was properly formatted
    $savedPenduduk = Penduduk::find($penduduk->id);

    // This test depends on the actual implementation of mutators
    // Adjust based on actual model behavior
    expect($savedPenduduk->nik)->toBeString();
});