<?php

namespace Modules\MedBloodBank\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Modules\MedBloodBank\Entities\MbbDonation;
use Modules\MedBloodBank\Entities\MbbDonor;
use Modules\MedBloodBank\Services\BloodBankService;
use Yajra\DataTables\Facades\DataTables;

/**
 * Donation entry + screening (SIFA P6-T6).
 *
 * - store(): the eligibility-gated collection entry (→ quarantined + auto expiry).
 * - screen(): the screening modal — all four negative → available; any reactive
 *   → discarded + permanent donor deferral. Guarded by mbb.screening.result.
 */
class DonationController extends MedBloodBankBaseController
{
    public function __construct(private BloodBankService $service)
    {
    }

    public function index(Request $request)
    {
        $this->guard('mbb.donations.manage');

        if ($request->ajax()) {
            $query = MbbDonation::forBusiness($this->businessId())
                ->leftJoin('mbb_donors', 'mbb_donors.id', '=', 'mbb_donations.donor_id')
                ->leftJoin('contacts', 'contacts.id', '=', 'mbb_donors.contact_id')
                ->select([
                    'mbb_donations.id',
                    'mbb_donations.bag_no',
                    'mbb_donations.product_type',
                    'mbb_donations.blood_group',
                    'mbb_donations.collected_at',
                    'mbb_donations.expiry_date',
                    'mbb_donations.screening_status',
                    'mbb_donations.status',
                    'contacts.name as donor_name',
                    'contacts.supplier_business_name',
                ]);

            return DataTables::of($query)
                ->editColumn('donor_name', fn ($r) => e(trim($r->donor_name ?? '') ?: trim($r->supplier_business_name ?? '') ?: '—'))
                ->editColumn('product_type', fn ($r) => __('medbloodbank::lang.product_' . $r->product_type))
                ->editColumn('collected_at', fn ($r) => $r->collected_at ? \Carbon\Carbon::parse($r->collected_at)->toDateString() : '—')
                ->editColumn('expiry_date', fn ($r) => $r->expiry_date ?: '—')
                ->editColumn('screening_status', fn ($r) => $this->screeningLabel($r->screening_status))
                ->editColumn('status', fn ($r) => $this->statusLabel($r->status))
                ->addColumn('action', function ($r) {
                    $btns = '';
                    if (auth()->user()->can('mbb.screening.result') && in_array($r->status, ['collected', 'quarantined'])) {
                        $btns .= '<button class="btn btn-xs btn-warning mbb-modal-btn" data-href="'
                            . route('mbb.donations.screen.form', $r->id) . '"><i class="fa fa-vial"></i> '
                            . __('medbloodbank::lang.enter_screening') . '</button> ';
                    }

                    return $btns ?: '<span class="text-muted">—</span>';
                })
                ->rawColumns(['screening_status', 'status', 'action'])
                ->make(true);
        }

        return view('medbloodbank::donations.index');
    }

    public function create()
    {
        $this->guard('mbb.donations.manage');

        return view('medbloodbank::donations.form', [
            'donors'        => $this->donorOptions(),
            'donationTypes' => MbbDonation::DONATION_TYPES,
            'productTypes'  => MbbDonation::PRODUCT_TYPES,
            'bloodGroups'   => MbbDonation::BLOOD_GROUPS,
        ]);
    }

    public function store(Request $request)
    {
        $this->guard('mbb.donations.manage');

        $data = $this->validate($request, [
            'donor_id'      => 'required|integer',
            'bag_no'        => 'required|string|max:60',
            'donation_type' => 'required|in:' . implode(',', MbbDonation::DONATION_TYPES),
            'product_type'  => 'required|in:' . implode(',', MbbDonation::PRODUCT_TYPES),
            'volume_ml'     => 'nullable|integer|min:0',
            'blood_group'   => 'required|in:' . implode(',', MbbDonation::BLOOD_GROUPS),
            'collected_at'  => 'nullable|date',
        ]);

        $donor = MbbDonor::forBusiness($this->businessId())->find($data['donor_id']);
        if (! $donor) {
            return $this->fail(__('medbloodbank::lang.donor_not_found'));
        }

        // Enforce unique bag_no per business.
        if (MbbDonation::forBusiness($this->businessId())->where('bag_no', $data['bag_no'])->exists()) {
            return $this->fail(__('medbloodbank::lang.bag_no_taken'));
        }

        try {
            $data['collected_by'] = $this->userId();
            $donation = $this->service->recordDonation($donor, $data);

            return $this->ok(__('medbloodbank::lang.donation_saved', ['bag' => $donation->bag_no]));
        } catch (ValidationException $e) {
            // Eligibility failure — surface the human message.
            return $this->fail($this->firstError($e));
        } catch (\Exception $e) {
            \Log::emergency($e->getMessage());

            return $this->fail();
        }
    }

    /** The screening modal form. */
    public function screenForm($id)
    {
        $this->guard('mbb.screening.result');

        $donation = MbbDonation::forBusiness($this->businessId())->findOrFail($id);

        return view('medbloodbank::donations.screen', [
            'donation' => $donation,
            'markers'  => MbbDonation::SCREENING_MARKERS,
        ]);
    }

    public function screen(Request $request, $id)
    {
        $this->guard('mbb.screening.result');

        $donation = MbbDonation::forBusiness($this->businessId())->findOrFail($id);

        if (! in_array($donation->status, ['collected', 'quarantined'])) {
            return $this->fail(__('medbloodbank::lang.screening_locked'));
        }

        $data = $this->validate($request, [
            'hiv'      => 'required|in:negative,reactive,pending',
            'hbv'      => 'required|in:negative,reactive,pending',
            'hcv'      => 'required|in:negative,reactive,pending',
            'syphilis' => 'required|in:negative,reactive,pending',
        ]);

        try {
            $donation = $this->service->enterScreening($donation, $data);

            $msg = [
                'passed' => __('medbloodbank::lang.screening_passed_msg'),
                'failed' => __('medbloodbank::lang.screening_failed_msg'),
                'pending' => __('medbloodbank::lang.screening_pending_saved'),
            ][$donation->screening_status] ?? __('medbloodbank::lang.saved');

            return $this->ok($msg);
        } catch (\Exception $e) {
            \Log::emergency($e->getMessage());

            return $this->fail();
        }
    }

    // ── helpers ──────────────────────────────────────────────────────────

    private function donorOptions(): array
    {
        return MbbDonor::forBusiness($this->businessId())
            ->leftJoin('contacts', 'contacts.id', '=', 'mbb_donors.contact_id')
            ->orderBy('contacts.name')
            ->get(['mbb_donors.id', 'mbb_donors.blood_group', 'contacts.name', 'contacts.supplier_business_name', 'contacts.mobile'])
            ->map(fn ($d) => [
                'id'          => $d->id,
                'name'        => trim($d->name ?? '') ?: trim($d->supplier_business_name ?? '') ?: ('#' . $d->id),
                'mobile'      => $d->mobile,
                'blood_group' => $d->blood_group,
            ])
            ->all();
    }

    private function screeningLabel(string $s): string
    {
        $map = ['pending' => 'default', 'passed' => 'success', 'failed' => 'danger'];

        return '<span class="label label-' . ($map[$s] ?? 'default') . '">' . __('medbloodbank::lang.screening_' . $s) . '</span>';
    }

    private function statusLabel(string $s): string
    {
        $map = [
            'collected' => 'default', 'quarantined' => 'warning', 'available' => 'success',
            'reserved' => 'info', 'issued' => 'primary', 'transfused' => 'primary',
            'expired' => 'danger', 'discarded' => 'danger',
        ];

        return '<span class="label label-' . ($map[$s] ?? 'default') . '">' . __('medbloodbank::lang.bag_status_' . $s) . '</span>';
    }

    private function firstError(ValidationException $e): string
    {
        foreach ($e->errors() as $msgs) {
            if (! empty($msgs)) {
                return $msgs[0];
            }
        }

        return __('messages.something_went_wrong');
    }
}
