<?php

use App\Models\User;
use App\Settings\HomepageSettings;
use App\Settings\HRSettings;
use App\Settings\SocialMediaSettings;
use App\Settings\SystemSettings;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Inertia\Testing\AssertableInertia as Assert;

uses(RefreshDatabase::class);

/*
|--------------------------------------------------------------------------
| AUTHENTICATION
|--------------------------------------------------------------------------
*/

test('guests are redirected to the login page', function () {
    $response = $this->get(route('admin.settings.index'));
    $response->assertRedirect(route('login'));
});

test('guest cannot update system settings', function () {
    $response = $this->put(route('admin.settings.update-system'), [
        'app_name' => 'Unauthorized',
    ]);
    $response->assertRedirect(route('login'));
});

test('guest cannot update homepage settings', function () {
    $response = $this->put(route('admin.settings.update-homepage'), [
        'hero_image_key' => 'unauthorized/image.jpg',
    ]);
    $response->assertRedirect(route('login'));
});

test('guest cannot update social media settings', function () {
    $response = $this->put(route('admin.settings.update-social-media'), [
        'instagram_url' => 'https://unauthorized.com',
    ]);
    $response->assertRedirect(route('login'));
});

test('guest cannot update hr settings', function () {
    $response = $this->put(route('admin.settings.update-hr'), [
        'scheduled_check_in_time' => '09:00',
    ]);
    $response->assertRedirect(route('login'));
});

/*
|--------------------------------------------------------------------------
| INDEX PAGE
|--------------------------------------------------------------------------
*/

test('authenticated users can visit the settings page', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->get(route('admin.settings.index'));
    $response->assertOk();
});

test('settings page renders with correct inertia component', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->get(route('admin.settings.index'));
    $response->assertInertia(fn (Assert $page) => $page
        ->component('admin/settings/index')
        ->has('system')
        ->has('homepage')
        ->has('socialMedia')
        ->has('hr')
    );
});

test('settings page contains system data', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $system = app(SystemSettings::class);

    $response = $this->get(route('admin.settings.index'));
    $response->assertInertia(fn (Assert $page) => $page
        ->where('system.app_name', $system->app_name)
        ->where('system.email', $system->email)
        ->where('system.phone', $system->phone)
    );
});

test('settings page contains hr data', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $hr = app(HRSettings::class);

    $response = $this->get(route('admin.settings.index'));
    $response->assertInertia(fn (Assert $page) => $page
        ->where('hr.scheduled_check_in_time', $hr->scheduled_check_in_time)
        ->where('hr.scheduled_check_out_time', $hr->scheduled_check_out_time)
        ->where('hr.late_penalty_amount', $hr->late_penalty_amount)
        ->where('hr.absent_penalty_amount', $hr->absent_penalty_amount)
    );
});

/*
|--------------------------------------------------------------------------
| UPDATE SYSTEM
|--------------------------------------------------------------------------
*/

test('user can update system settings with valid data', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-system'), [
        'app_name' => 'DST Collection Updated',
        'about_app' => 'Tentang DST Collection',
        'address' => 'Jl. Test No. 123',
        'email' => 'test@dst.com',
        'phone' => '081234567890',
    ]);

    $response
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('admin.settings.index'));

    $settings = app(SystemSettings::class);
    expect($settings->app_name)->toBe('DST Collection Updated');
    expect($settings->about_app)->toBe('Tentang DST Collection');
    expect($settings->address)->toBe('Jl. Test No. 123');
    expect($settings->email)->toBe('test@dst.com');
    expect($settings->phone)->toBe('081234567890');
});

test('system app_name is required', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-system'), [
        'app_name' => '',
    ]);

    $response->assertSessionHasErrors('app_name');
});

test('system email must be valid email format', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-system'), [
        'app_name' => 'DST',
        'email' => 'not-an-email',
    ]);

    $response->assertSessionHasErrors('email');
});

test('system app_name must not exceed 255 characters', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-system'), [
        'app_name' => str_repeat('a', 256),
    ]);

    $response->assertSessionHasErrors('app_name');
});

test('system about_app must not exceed 2000 characters', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-system'), [
        'app_name' => 'DST',
        'about_app' => str_repeat('a', 2001),
    ]);

    $response->assertSessionHasErrors('about_app');
});

test('system address must not exceed 500 characters', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-system'), [
        'app_name' => 'DST',
        'address' => str_repeat('a', 501),
    ]);

    $response->assertSessionHasErrors('address');
});

test('system phone must not exceed 20 characters', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-system'), [
        'app_name' => 'DST',
        'phone' => str_repeat('1', 21),
    ]);

    $response->assertSessionHasErrors('phone');
});

test('system nullable fields can be empty', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-system'), [
        'app_name' => 'DST',
        'about_app' => '',
        'address' => '',
        'email' => '',
        'phone' => '',
    ]);

    $response->assertSessionHasNoErrors();
});

/*
|--------------------------------------------------------------------------
| UPDATE HOMEPAGE
|--------------------------------------------------------------------------
*/

test('user can update homepage settings with valid data', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-homepage'), [
        'hero_image_key' => 'homepage/hero/2026/07/31/abc123/hero.jpg',
        'about_image_key' => 'homepage/about/2026/07/31/def456/about.jpg',
        'gallery_image_keys' => ['homepage/gallery/2026/07/31/g1/img.jpg', 'homepage/gallery/2026/07/31/g2/img.jpg'],
    ]);

    $response
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('admin.settings.index'));

    $settings = app(HomepageSettings::class);
    expect($settings->hero_image_url)->toBe('homepage/hero/2026/07/31/abc123/hero.jpg');
    expect($settings->about_image_url)->toBe('homepage/about/2026/07/31/def456/about.jpg');
    expect($settings->gallery_images)->toBe(['homepage/gallery/2026/07/31/g1/img.jpg', 'homepage/gallery/2026/07/31/g2/img.jpg']);
});

test('homepage fields are nullable', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-homepage'), [
        'hero_image_key' => null,
        'about_image_key' => null,
    ]);

    $response->assertSessionHasNoErrors();
});

test('homepage hero_image_key must not exceed 2000 characters', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-homepage'), [
        'hero_image_key' => str_repeat('a', 2001),
    ]);

    $response->assertSessionHasErrors('hero_image_key');
});

test('homepage gallery_image_keys must be array', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-homepage'), [
        'gallery_image_keys' => 'not-an-array',
    ]);

    $response->assertSessionHasErrors('gallery_image_keys');
});

test('homepage gallery_image_keys items must not exceed 2000 characters', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-homepage'), [
        'gallery_image_keys' => [str_repeat('a', 2001)],
    ]);

    $response->assertSessionHasErrors('gallery_image_keys.0');
});

/*
|--------------------------------------------------------------------------
| UPDATE SOCIAL MEDIA
|--------------------------------------------------------------------------
*/

test('user can update social media settings with valid data', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-social-media'), [
        'instagram_url' => 'https://instagram.com/dst',
        'facebook_url' => 'https://facebook.com/dst',
        'tiktok_url' => 'https://tiktok.com/@dst',
    ]);

    $response
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('admin.settings.index'));

    $settings = app(SocialMediaSettings::class);
    expect($settings->instagram_url)->toBe('https://instagram.com/dst');
    expect($settings->facebook_url)->toBe('https://facebook.com/dst');
    expect($settings->tiktok_url)->toBe('https://tiktok.com/@dst');
});

test('social media fields are nullable', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-social-media'), [
        'instagram_url' => null,
        'facebook_url' => null,
        'tiktok_url' => null,
    ]);

    $response->assertSessionHasNoErrors();
});

test('social media instagram_url must not exceed 500 characters', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-social-media'), [
        'instagram_url' => str_repeat('a', 501),
    ]);

    $response->assertSessionHasErrors('instagram_url');
});

test('social media facebook_url must not exceed 500 characters', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-social-media'), [
        'facebook_url' => str_repeat('a', 501),
    ]);

    $response->assertSessionHasErrors('facebook_url');
});

test('social media tiktok_url must not exceed 500 characters', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-social-media'), [
        'tiktok_url' => str_repeat('a', 501),
    ]);

    $response->assertSessionHasErrors('tiktok_url');
});

/*
|--------------------------------------------------------------------------
| UPDATE HR
|--------------------------------------------------------------------------
*/

test('user can update hr settings with valid data', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-hr'), [
        'scheduled_check_in_time' => '09:00',
        'scheduled_check_out_time' => '18:00',
        'late_penalty_amount' => 10000,
        'absent_penalty_amount' => 50000,
    ]);

    $response
        ->assertSessionHasNoErrors()
        ->assertRedirect(route('admin.settings.index'));

    $settings = app(HRSettings::class);
    expect($settings->scheduled_check_in_time)->toBe('09:00');
    expect($settings->scheduled_check_out_time)->toBe('18:00');
    expect($settings->late_penalty_amount)->toBe(10000);
    expect($settings->absent_penalty_amount)->toBe(50000);
});

test('hr scheduled_check_in_time is required', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-hr'), [
        'scheduled_check_in_time' => '',
        'scheduled_check_out_time' => '18:00',
        'late_penalty_amount' => 0,
        'absent_penalty_amount' => 0,
    ]);

    $response->assertSessionHasErrors('scheduled_check_in_time');
});

test('hr scheduled_check_out_time is required', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-hr'), [
        'scheduled_check_in_time' => '09:00',
        'scheduled_check_out_time' => '',
        'late_penalty_amount' => 0,
        'absent_penalty_amount' => 0,
    ]);

    $response->assertSessionHasErrors('scheduled_check_out_time');
});

test('hr late_penalty_amount is required', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-hr'), [
        'scheduled_check_in_time' => '09:00',
        'scheduled_check_out_time' => '18:00',
        'late_penalty_amount' => '',
        'absent_penalty_amount' => 0,
    ]);

    $response->assertSessionHasErrors('late_penalty_amount');
});

test('hr absent_penalty_amount is required', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-hr'), [
        'scheduled_check_in_time' => '09:00',
        'scheduled_check_out_time' => '18:00',
        'late_penalty_amount' => 0,
        'absent_penalty_amount' => '',
    ]);

    $response->assertSessionHasErrors('absent_penalty_amount');
});

test('hr penalty amounts must be at least 0', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-hr'), [
        'scheduled_check_in_time' => '09:00',
        'scheduled_check_out_time' => '18:00',
        'late_penalty_amount' => -1,
        'absent_penalty_amount' => -1,
    ]);

    $response->assertSessionHasErrors(['late_penalty_amount', 'absent_penalty_amount']);
});

test('hr penalty amounts must be integers', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-hr'), [
        'scheduled_check_in_time' => '09:00',
        'scheduled_check_out_time' => '18:00',
        'late_penalty_amount' => 1000.50,
        'absent_penalty_amount' => 2000.75,
    ]);

    $response->assertSessionHasErrors(['late_penalty_amount', 'absent_penalty_amount']);
});

test('hr time fields must not exceed 5 characters', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $response = $this->put(route('admin.settings.update-hr'), [
        'scheduled_check_in_time' => '09:000',
        'scheduled_check_out_time' => '18:000',
        'late_penalty_amount' => 0,
        'absent_penalty_amount' => 0,
    ]);

    $response->assertSessionHasErrors(['scheduled_check_in_time', 'scheduled_check_out_time']);
});

/*
|--------------------------------------------------------------------------
| EDGE CASES & DATA INTEGRITY
|--------------------------------------------------------------------------
*/

test('system settings default values exist', function () {
    $settings = app(SystemSettings::class);

    expect($settings->app_name)->not->toBeEmpty();
    expect($settings->about_app)->not->toBeNull();
    expect($settings->address)->not->toBeNull();
    expect($settings->email)->not->toBeNull();
    expect($settings->phone)->not->toBeNull();
});

test('hr settings default values exist', function () {
    $settings = app(HRSettings::class);

    expect($settings->scheduled_check_in_time)->not->toBeEmpty();
    expect($settings->scheduled_check_out_time)->not->toBeEmpty();
    expect($settings->late_penalty_amount)->toBeInt();
    expect($settings->absent_penalty_amount)->toBeInt();
});

test('updating one setting group does not affect others', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    $systemBefore = app(SystemSettings::class);
    $hrBefore = app(HRSettings::class);

    $this->put(route('admin.settings.update-system'), [
        'app_name' => 'Changed Name',
        'about_app' => $systemBefore->about_app,
        'address' => $systemBefore->address,
        'email' => $systemBefore->email,
        'phone' => $systemBefore->phone,
    ]);

    $systemAfter = app(SystemSettings::class);
    $hrAfter = app(HRSettings::class);

    expect($systemAfter->app_name)->toBe('Changed Name');
    expect($hrAfter->scheduled_check_in_time)->toBe($hrBefore->scheduled_check_in_time);
    expect($hrAfter->late_penalty_amount)->toBe($hrBefore->late_penalty_amount);
});

/*
|--------------------------------------------------------------------------
| REALISTIC USER SCENARIOS
|--------------------------------------------------------------------------
*/

test('user updates all settings groups in sequence', function () {
    $user = User::factory()->create();
    $this->actingAs($user);

    // Update system
    $this->put(route('admin.settings.update-system'), [
        'app_name' => 'DST Updated',
        'about_app' => 'About Updated',
        'address' => 'Address Updated',
        'email' => 'updated@dst.com',
        'phone' => '089999999999',
    ])->assertSessionHasNoErrors();

    // Update homepage
    $this->put(route('admin.settings.update-homepage'), [
        'hero_image_key' => 'homepage/hero/2026/07/31/new-hero.jpg',
        'about_image_key' => 'homepage/about/2026/07/31/new-about.jpg',
    ])->assertSessionHasNoErrors();

    // Update social media
    $this->put(route('admin.settings.update-social-media'), [
        'instagram_url' => 'https://instagram.com/newdst',
        'facebook_url' => 'https://facebook.com/newdst',
        'tiktok_url' => 'https://tiktok.com/@newdst',
    ])->assertSessionHasNoErrors();

    // Update HR
    $this->put(route('admin.settings.update-hr'), [
        'scheduled_check_in_time' => '08:30',
        'scheduled_check_out_time' => '17:30',
        'late_penalty_amount' => 15000,
        'absent_penalty_amount' => 75000,
    ])->assertSessionHasNoErrors();

    // Verify all settings persisted
    $system = app(SystemSettings::class);
    $homepage = app(HomepageSettings::class);
    $socialMedia = app(SocialMediaSettings::class);
    $hr = app(HRSettings::class);

    expect($system->app_name)->toBe('DST Updated');
    expect($homepage->hero_image_url)->toBe('homepage/hero/2026/07/31/new-hero.jpg');
    expect($socialMedia->instagram_url)->toBe('https://instagram.com/newdst');
    expect($hr->scheduled_check_in_time)->toBe('08:30');
    expect($hr->late_penalty_amount)->toBe(15000);
});
