<?php

namespace Tests\Feature;

use App\Models\Kategori;
use App\Models\ObatKeluar;
use App\Models\ObatMasuk;
use App\Models\Satuan;
use App\Models\User;
use Tests\DatabaseTestCase;

class ObatKeluarTest extends DatabaseTestCase
{
    private User $user;
    private ObatMasuk $obatMasuk;

    protected function setUp(): void
    {
        parent::setUp();
        $this->user = User::factory()->create(['role' => 'apoteker']);
        $this->actingAs($this->user);

        $kategori = Kategori::create(['nama' => 'Antibiotik']);
        $satuan   = Satuan::create(['nama' => 'Tablet']);

        $this->obatMasuk = ObatMasuk::create([
            'nama_obat'          => 'Amoxicillin',
            'kategori_id'        => $kategori->id,
            'satuan_id'          => $satuan->id,
            'kode_batch'         => 'BTH-001',
            'stok'               => 100,
            'tanggal_penerimaan' => now()->toDateString(),
            'tanggal_kadaluarsa' => now()->addYear()->toDateString(),
            'user_id'            => $this->user->id,
        ]);
    }

    private function validData(array $overrides = []): array
    {
        return array_merge([
            'obat_masuk_id'       => $this->obatMasuk->id,
            'kode_batch'          => 'BTH-001',
            'jumlah'              => 10,
            'tujuan_pemakaian'    => 'Penggunaan internal',
            'tanggal_kadaluarsa'  => now()->addYear()->toDateString(),
            'tanggal_pengeluaran' => now()->toDateString(),
            'nama_petugas'        => 'Petugas A',
            'nama_penerima'       => 'Penerima B',
        ], $overrides);
    }

    // ─────────────────────────────────────────
    // index
    // ─────────────────────────────────────────

    public function test_index_returns_200(): void
    {
        $response = $this->get(route('obat-keluar.index'));
        $response->assertStatus(200);
    }

    public function test_index_guest_redirects_to_login(): void
    {
        auth()->logout();
        $response = $this->get(route('obat-keluar.index'));
        $response->assertRedirect(route('login'));
    }

    public function test_index_filter_by_status(): void
    {
        ObatKeluar::create(array_merge($this->validData(['jumlah' => 5]), [
            'nama_obat' => 'Amoxicillin',
            'status'    => 'proses',
            'user_id'   => $this->user->id,
        ]));

        $response = $this->get(route('obat-keluar.index', ['status' => 'proses']));
        $response->assertStatus(200);
    }

    public function test_index_search(): void
    {
        ObatKeluar::create(array_merge($this->validData(), [
            'nama_obat' => 'Amoxicillin',
            'kode_batch' => 'BTH-001',
            'user_id'   => $this->user->id,
        ]));

        ObatKeluar::create(array_merge($this->validData(), [
            'nama_obat' => 'Paracetamol',
            'kode_batch' => 'BTH-002',
            'user_id'   => $this->user->id,
        ]));

        $response = $this->get(route('obat-keluar.index', ['search' => 'Paracetamol']));
        $data = $response->viewData('obatKeluars');
        $names = $data->pluck('nama_obat')->toArray();
        
        $this->assertContains('Paracetamol', $names);
        $this->assertNotContains('Amoxicillin', $names);
    }

    // ─────────────────────────────────────────
    // create, show, edit
    // ─────────────────────────────────────────

    public function test_create_returns_200(): void
    {
        $response = $this->get(route('obat-keluar.create'));
        $response->assertStatus(200);
    }

    public function test_show_returns_200(): void
    {
        $keluar = ObatKeluar::create(array_merge($this->validData(), [
            'nama_obat' => 'Amoxicillin',
            'status'    => 'proses',
            'user_id'   => $this->user->id,
        ]));
        $response = $this->get(route('obat-keluar.show', $keluar));
        $response->assertStatus(200);
    }

    public function test_edit_returns_200(): void
    {
        $keluar = ObatKeluar::create(array_merge($this->validData(), [
            'nama_obat' => 'Amoxicillin',
            'status'    => 'proses',
            'user_id'   => $this->user->id,
        ]));
        $response = $this->get(route('obat-keluar.edit', $keluar));
        $response->assertStatus(200);
    }

    // ─────────────────────────────────────────
    // store — berhasil
    // ─────────────────────────────────────────

    public function test_store_creates_obat_keluar_and_decrements_stok(): void
    {
        $initialStok = $this->obatMasuk->stok; // 100

        $response = $this->post(route('obat-keluar.store'), $this->validData(['jumlah' => 10]));

        $response->assertRedirect(route('obat-keluar.index'));
        $response->assertSessionHas('success');

        $this->assertDatabaseHas('obat_keluars', [
            'obat_masuk_id' => $this->obatMasuk->id,
            'jumlah'        => 10,
            'nama_obat'     => 'Amoxicillin',
        ]);

        // Stok berkurang dari 100 menjadi 90
        $this->assertEquals($initialStok - 10, $this->obatMasuk->fresh()->stok);
    }

    public function test_store_sets_user_id_and_nama_obat_automatically(): void
    {
        $this->post(route('obat-keluar.store'), $this->validData(['jumlah' => 5]));

        $this->assertDatabaseHas('obat_keluars', [
            'user_id'   => $this->user->id,
            'nama_obat' => 'Amoxicillin',
        ]);
    }

    // ─────────────────────────────────────────
    // store — gagal karena stok
    // ─────────────────────────────────────────

    public function test_store_fails_when_jumlah_exceeds_stok(): void
    {
        $response = $this->post(route('obat-keluar.store'), $this->validData(['jumlah' => 200])); // stok cuma 100

        // Harus kembali ke form dengan error jumlah
        $response->assertSessionHasErrors('jumlah');
    }

    public function test_store_stok_unchanged_when_validation_fails(): void
    {
        $this->post(route('obat-keluar.store'), $this->validData(['jumlah' => 200]));

        $this->assertEquals(100, $this->obatMasuk->fresh()->stok);
    }

    // ─────────────────────────────────────────
    // store — validasi field wajib
    // ─────────────────────────────────────────

    public function test_store_fails_without_required_fields(): void
    {
        $response = $this->post(route('obat-keluar.store'), []);
        $response->assertSessionHasErrors([
            'obat_masuk_id',
            'kode_batch',
            'jumlah',
            'tujuan_pemakaian',
            'tanggal_kadaluarsa',
            'tanggal_pengeluaran',
            'nama_petugas',
            'nama_penerima',
        ]);
    }

    // ─────────────────────────────────────────
    // update — perubahan jumlah
    // ─────────────────────────────────────────

    public function test_update_adjusts_stok_when_jumlah_increases(): void
    {
        // Buat obat keluar awal dengan jumlah 10 → stok jadi 90
        $keluar = ObatKeluar::create(array_merge($this->validData(['jumlah' => 10]), [
            'nama_obat' => 'Amoxicillin',
            'status'    => 'proses',
            'user_id'   => $this->user->id,
        ]));
        $this->obatMasuk->decrement('stok', 10); // stok = 90

        // Update jumlah menjadi 30 (selisih +20, stok dari 90 → 70)
        $response = $this->put(
            route('obat-keluar.update', $keluar),
            $this->validData(['jumlah' => 30])
        );

        $response->assertRedirect(route('obat-keluar.index'));
        $this->assertEquals(70, $this->obatMasuk->fresh()->stok);
    }

    public function test_update_adjusts_stok_when_jumlah_decreases(): void
    {
        // Buat obat keluar awal dengan jumlah 20 → stok jadi 80
        $keluar = ObatKeluar::create(array_merge($this->validData(['jumlah' => 20]), [
            'nama_obat' => 'Amoxicillin',
            'status'    => 'proses',
            'user_id'   => $this->user->id,
        ]));
        $this->obatMasuk->decrement('stok', 20); // stok = 80

        // Update jumlah menjadi 10 (selisih −10, stok dari 80 → 90)
        $response = $this->put(
            route('obat-keluar.update', $keluar),
            $this->validData(['jumlah' => 10])
        );

        $response->assertRedirect(route('obat-keluar.index'));
        $this->assertEquals(90, $this->obatMasuk->fresh()->stok);
    }

    public function test_update_fails_when_increased_jumlah_exceeds_available_stok(): void
    {
        // Stok awal 100, keluar 10 → stok = 90
        $keluar = ObatKeluar::create(array_merge($this->validData(['jumlah' => 10]), [
            'nama_obat' => 'Amoxicillin',
            'status'    => 'proses',
            'user_id'   => $this->user->id,
        ]));
        $this->obatMasuk->decrement('stok', 10);

        // Coba update ke 200 (selisih = +190, stok hanya 90)
        $response = $this->put(
            route('obat-keluar.update', $keluar),
            $this->validData(['jumlah' => 200])
        );

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

    public function test_update_fails_without_required_fields(): void
    {
        $keluar = ObatKeluar::create(array_merge($this->validData(['jumlah' => 10]), [
            'nama_obat' => 'Amoxicillin',
            'user_id'   => $this->user->id,
        ]));

        $response = $this->put(route('obat-keluar.update', $keluar), []);

        $response->assertSessionHasErrors([
            'obat_masuk_id',
            'kode_batch',
            'jumlah',
            'tujuan_pemakaian',
            'tanggal_kadaluarsa',
            'tanggal_pengeluaran',
            'nama_petugas',
            'nama_penerima',
        ]);
    }

    // ─────────────────────────────────────────
    // destroy — stok dikembalikan
    // ─────────────────────────────────────────

    public function test_destroy_deletes_obat_keluar_and_restores_stok(): void
    {
        // Buat keluar jumlah 15 → stok jadi 85
        $keluar = ObatKeluar::create(array_merge($this->validData(['jumlah' => 15]), [
            'nama_obat' => 'Amoxicillin',
            'status'    => 'proses',
            'user_id'   => $this->user->id,
        ]));
        $this->obatMasuk->decrement('stok', 15);

        $response = $this->delete(route('obat-keluar.destroy', $keluar));

        $response->assertRedirect(route('obat-keluar.index'));
        $response->assertSessionHas('success');

        // Stok dikembalikan → 100
        $this->assertEquals(100, $this->obatMasuk->fresh()->stok);
        $this->assertDatabaseMissing('obat_keluars', ['id' => $keluar->id]);
    }

    // ─────────────────────────────────────────
    // superadmin access
    // ─────────────────────────────────────────

    public function test_superadmin_can_access_index(): void
    {
        $superadmin = User::factory()->create(['role' => 'superadmin']);
        $this->actingAs($superadmin);
        
        $response = $this->get(route('obat-keluar.index'));
        $response->assertStatus(200);
    }

    public function test_superadmin_can_access_show(): void
    {
        $superadmin = User::factory()->create(['role' => 'superadmin']);
        $this->actingAs($superadmin);
        
        $keluar = ObatKeluar::create(array_merge($this->validData(), [
            'nama_obat' => 'Amoxicillin',
            'status'    => 'proses',
            'user_id'   => $this->user->id,
        ]));
        $response = $this->get(route('obat-keluar.show', $keluar));
        $response->assertStatus(200);
    }

    public function test_superadmin_can_access_create_store_edit_update_destroy(): void
    {
        $superadmin = User::factory()->create(['role' => 'superadmin']);
        $this->actingAs($superadmin);
        
        $keluar = ObatKeluar::create(array_merge($this->validData(), [
            'nama_obat' => 'Amoxicillin',
            'status'    => 'proses',
            'user_id'   => $this->user->id,
        ]));
        
        $this->get(route('obat-keluar.create'))->assertStatus(200);
        $this->post(route('obat-keluar.store'), $this->validData(['jumlah' => 10]))
            ->assertRedirect(route('obat-keluar.index'));
        $this->assertDatabaseHas('obat_keluars', ['user_id' => $superadmin->id, 'jumlah' => 10]);
        $this->get(route('obat-keluar.edit', $keluar))->assertStatus(200);
        $this->put(route('obat-keluar.update', $keluar), $this->validData(['jumlah' => 8]))
            ->assertRedirect(route('obat-keluar.index'));
        $this->assertDatabaseHas('obat_keluars', ['id' => $keluar->id, 'jumlah' => 8]);
        $this->delete(route('obat-keluar.destroy', $keluar))->assertRedirect(route('obat-keluar.index'));
        $this->assertDatabaseMissing('obat_keluars', ['id' => $keluar->id]);
    }
}
