<?php

namespace App\Http\Controllers;

use App\BioCabinet;
use App\BioRack;
use App\BioSpecimen;
use App\Periksa;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Session;
use Validator;

class BiorepositoryController extends Controller
{
    public function index()
    {
        if (Session::get('previlage') == '') {
            return redirect('/login');
        }

        $data = [];
        $data['cabinetOptions'] = BioCabinet::orderBy('name', 'ASC')->get();
        $data['totalCabinets'] = BioCabinet::count();
        $data['totalRacks'] = BioRack::count();
        $data['totalSpecimens'] = BioSpecimen::count();
        $data['specimenRows'] = BioSpecimen::with(['cabinet', 'rack'])
            ->orderBy('stored_at', 'DESC')
            ->orderBy('id', 'DESC')
            ->get();

        $data['oldestSpecimen'] = BioSpecimen::with(['cabinet', 'rack'])
            ->whereNotNull('stored_at')
            ->orderBy('stored_at', 'ASC')
            ->first();

        $data['oldestStorageDays'] = 0;
        if ($data['oldestSpecimen']) {
            $data['oldestStorageDays'] = Carbon::parse($data['oldestSpecimen']->stored_at)->diffInDays(Carbon::now());
        }

        return view('admin.biorepository', $data);
    }

    public function storeCabinet(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'code' => 'required|max:50|unique:bio_cabinets,code',
            'name' => 'required|max:150',
            'location' => 'nullable|max:200',
            'notes' => 'nullable',
        ]);

        if ($validator->fails()) {
            return back()->withErrors($validator)->withInput();
        }

        BioCabinet::create([
            'code' => $request->input('code'),
            'name' => $request->input('name'),
            'location' => $request->input('location'),
            'notes' => $request->input('notes'),
        ]);

        return redirect('/biorepository')->with('success', 'Lemari biorepository berhasil ditambahkan.');
    }

    public function storeRack(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'cabinet_id' => 'required|exists:bio_cabinets,id',
            'code' => 'required|max:50',
            'name' => 'required|max:150',
            'slot_count' => 'required|integer|min:1|max:20',
            'level' => 'required|integer|min:4|max:6',
            'box_number' => 'required|integer|min:1|max:20',
            'capacity' => 'required|integer|min:16|max:100',
            'notes' => 'nullable',
        ]);

        if ($validator->fails()) {
            return back()->withErrors($validator)->withInput();
        }

        $exists = BioRack::where('cabinet_id', $request->input('cabinet_id'))
            ->where('code', $request->input('code'))
            ->exists();

        if ($exists) {
            return back()->withErrors(['code' => 'Kode rack sudah dipakai pada lemari ini.'])->withInput();
        }

        $nextRackNumber = ((int) BioRack::where('cabinet_id', $request->input('cabinet_id'))->max('rack_number')) + 1;

        BioRack::create([
            'cabinet_id' => $request->input('cabinet_id'),
            'code' => $request->input('code'),
            'name' => $request->input('name'),
            'slot_count' => $request->input('slot_count'),
            'level' => $request->input('level'),
            'rack_number' => $nextRackNumber,
            'box_number' => $request->input('box_number'),
            'capacity' => $request->input('capacity'),
            'notes' => $request->input('notes'),
        ]);

        return redirect('/biorepository')->with('success', 'Rack berhasil ditambahkan.');
    }

    public function storeSpecimen(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'rack_id'           => 'required|exists:bio_racks,id',
            'kategorisimpan'    => 'required|in:A,B,C,D',
            'shelfnomor'        => 'required|integer|min:1',
            'raknomor'          => 'required|integer|min:1',
            'slotnomor'         => 'required|integer|min:1',
            'boxnomor'          => 'required|integer|min:1',
            'tubenomor'         => 'required|integer|min:1',
            'nmbakteri'         => 'nullable|max:200',
            'strain'            => 'nullable|in:Gram Negatif,Gram Positif',
            'stored_at'         => 'required|date',
            'volume'            => 'nullable|numeric|min:0',
            'volume_ambil'      => 'nullable|numeric|min:0',
            'existing_specimen_id' => 'nullable|integer',
        ]);

        if ($validator->fails()) {
            return back()->withErrors($validator)->withInput();
        }

        $rack = BioRack::find($request->input('rack_id'));
        $expectedRackNo = $rack->rack_number ?: $rack->id;
        $slotCount = (int) ($rack->slot_count ?: 1);
        $boxCount = (int) ($rack->box_number ?: 1);

        if ((int) $request->input('raknomor') !== (int) $expectedRackNo) {
            return back()->withErrors(['slotnomor' => 'Posisi slot tidak sesuai dengan konfigurasi rack.'])->withInput();
        }

        if ((int) $request->input('slotnomor') < 1 || (int) $request->input('slotnomor') > $slotCount) {
            return back()->withErrors(['slotnomor' => 'Slot melebihi konfigurasi rack.'])->withInput();
        }

        if ((int) $request->input('shelfnomor') < 1 || (int) $request->input('shelfnomor') > (int) $rack->level) {
            return back()->withErrors(['shelfnomor' => 'Shelf melebihi konfigurasi slot.'])->withInput();
        }

        if ((int) $request->input('boxnomor') < 1 || (int) $request->input('boxnomor') > $boxCount) {
            return back()->withErrors(['boxnomor' => 'Box melebihi konfigurasi shelf.'])->withInput();
        }

        if ((int) $request->input('tubenomor') < 1 || (int) $request->input('tubenomor') > (int) $rack->capacity) {
            return back()->withErrors(['tubenomor' => 'Nomor tube melebihi kapasitas box pada shelf ini.'])->withInput();
        }

        $slotTaken = BioSpecimen::where('rack_id', $rack->id)
            ->where('slot_number', $request->input('slotnomor'))
            ->where('shelf_number', $request->input('shelfnomor'))
            ->where('box_number', $request->input('boxnomor'))
            ->where('tube_number', $request->input('tubenomor'))
            ->first();

        if ($slotTaken) {
            $existingId = (int) $request->input('existing_specimen_id');
            if ($existingId !== (int) $slotTaken->id) {
                return back()->withErrors(['tubenomor' => 'Posisi tube pada shelf ini sudah terisi spesimen.'])->withInput();
            }

            $volumeAmbil = (float) $request->input('volume_ambil');
            if ($volumeAmbil <= 0) {
                return back()->withErrors(['volume_ambil' => 'Isi volume yang diambil dari spesimen.'])->withInput();
            }

            $volumeSekarang = (float) ($slotTaken->volume ?? 0);
            if ($volumeAmbil > $volumeSekarang) {
                return back()->withErrors(['volume_ambil' => 'Volume diambil melebihi sisa volume spesimen.'])->withInput();
            }

            $slotTaken->volume = (string) ($volumeSekarang - $volumeAmbil);
            $slotTaken->save();

            return redirect('/biorepository')->with('success', 'Pengambilan volume berhasil. Sisa volume diperbarui.');
        }

        if (!$request->filled('nmbakteri') || !$request->filled('strain')) {
            return back()->withErrors(['nmbakteri' => 'Nama bakteri dan strain wajib diisi untuk spesimen baru.'])->withInput();
        }

        if (!$request->filled('volume')) {
            return back()->withErrors(['volume' => 'Volume awal spesimen wajib diisi.'])->withInput();
        }

        $atccByUser = strtoupper(preg_replace('/[^A-Za-z0-9]/', '', Session::get('nama', 'UNKNOWN')));
        if ($atccByUser === '') {
            $atccByUser = 'UNKNOWN';
        }

        $generatedCode = implode('-', [
            $request->input('kategorisimpan'),
            $request->input('shelfnomor'),
            $request->input('raknomor'),
            $request->input('slotnomor'),
            $request->input('boxnomor'),
            $request->input('tubenomor'),
        ]);

        $baseCode = $generatedCode;
        $counter = 1;
        while (BioSpecimen::where('specimen_code', $generatedCode)->exists()) {
            $counter++;
            $generatedCode = $baseCode.'-'.$counter;
        }
        $sampleid = $request->input('sampleid');
        if ($sampleid) {
            $cekdata = Periksa::where('nofoto', $sampleid)->first();
            if ($cekdata) {
                $sampleid = $cekdata->id;
            } else {
                $sampleid = null;
            }
        } else {
            $sampleid = null;
        }

        BioSpecimen::create([
            'cabinet_id' => $rack->cabinet_id,
            'rack_id' => $rack->id,
            'specimen_code' => $generatedCode,
            'specimen_name' => $request->input('nmbakteri'),
            'category_storage' => $request->input('kategorisimpan'),
            'shelf_number' => $request->input('shelfnomor'),
            'rack_number' => $request->input('raknomor'),
            'slot_number' => $request->input('slotnomor'),
            'box_number' => $request->input('boxnomor'),
            'tube_number' => $request->input('tubenomor'),
            'bacteria_name' => $request->input('nmbakteri'),
            'strain' => $request->input('strain'),
            'atcc' => $request->input('atcc') ?? $atccByUser,
            'input_by' => Session::get('nama'),
            'sampleid' => $sampleid,
            'stored_at' => $request->input('stored_at'),
            'storage_condition' => $this->mapStorageCondition($request->input('kategorisimpan')),
            'volume' => (string) $request->input('volume'),
            'notes' => $request->input('notes'),
        ]);

        return redirect('/biorepository')->with('success', 'Spesimen berhasil disimpan ke slot terpilih.');
    }

    public function deleteSpecimen($id)
    {
        if (Session::get('previlage') == '') {
            return redirect('/login');
        }

        $specimen = BioSpecimen::find($id);
        if (!$specimen) {
            return redirect('/biorepository')->withErrors(['specimen' => 'Data spesimen tidak ditemukan.']);
        }

        $specimen->delete();

        return redirect('/biorepository')->with('success', 'Spesimen berhasil dihapus.');
    }

    public function deleteRack($id)
    {
        if (Session::get('previlage') == '') {
            return redirect('/login');
        }

        $rack = BioRack::find($id);
        if (!$rack) {
            return redirect('/biorepository')->withErrors(['rack' => 'Data rack tidak ditemukan.']);
        }

        BioSpecimen::where('rack_id', $rack->id)->delete();
        $rack->delete();

        return redirect('/biorepository')->with('success', 'Rack dan semua spesimennya berhasil dihapus.');
    }

    public function deleteCabinet($id)
    {
        if (Session::get('previlage') == '') {
            return redirect('/login');
        }

        $cabinet = BioCabinet::find($id);
        if (!$cabinet) {
            return redirect('/biorepository')->withErrors(['cabinet' => 'Data lemari tidak ditemukan.']);
        }

        $rackIds = BioRack::where('cabinet_id', $cabinet->id)->pluck('id')->toArray();
        if (!empty($rackIds)) {
            BioSpecimen::whereIn('rack_id', $rackIds)->delete();
            BioRack::whereIn('id', $rackIds)->delete();
        }
        $cabinet->delete();

        return redirect('/biorepository')->with('success', 'Lemari beserta rack dan spesimennya berhasil dihapus.');
    }

    private function mapStorageCondition($category)
    {
        $mapping = [
            'A' => 'Suhu Ruang',
            'B' => '4 Derajat',
            'C' => '20 Derajat',
            'D' => '80 Derajat',
        ];

        return $mapping[$category] ?? 'Tidak Diketahui';
    }
}
