<?php

namespace Modules\MedBloodBank\Http\Controllers;

use App\Contact;
use Illuminate\Http\Request;
use Modules\MedBloodBank\Entities\MbbDonor;
use Yajra\DataTables\Facades\DataTables;

/**
 * Donor registry CRUD (SIFA P6-T6). A donor IS an ERP contact (type customer)
 * with the mbb_donors satellite — the create form uses a Select2 contact picker
 * fed by search(). Business-scoped; guarded by mbb.donors.manage.
 */
class DonorController extends MedBloodBankBaseController
{
    public function index(Request $request)
    {
        $this->guard('mbb.donors.manage');

        if ($request->ajax()) {
            $query = MbbDonor::forBusiness($this->businessId())
                ->leftJoin('contacts', 'contacts.id', '=', 'mbb_donors.contact_id')
                ->select([
                    'mbb_donors.id',
                    'mbb_donors.blood_group',
                    'mbb_donors.last_donation_at',
                    'mbb_donors.deferred_until',
                    'mbb_donors.total_donations',
                    'contacts.name as contact_name',
                    'contacts.supplier_business_name',
                    'contacts.mobile',
                ]);

            return DataTables::of($query)
                ->addColumn('donor_name', function ($r) {
                    $name = trim($r->contact_name ?? '') ?: trim($r->supplier_business_name ?? '') ?: ('#' . $r->id);

                    return e($name) . ($r->mobile ? ' <small class="text-muted">(' . e($r->mobile) . ')</small>' : '');
                })
                ->editColumn('blood_group', fn ($r) => $r->blood_group ?: '—')
                ->editColumn('last_donation_at', fn ($r) => $r->last_donation_at
                    ? \Carbon\Carbon::parse($r->last_donation_at)->toDateString() : '—')
                ->addColumn('eligibility', function ($r) {
                    $donor = MbbDonor::find($r->id);
                    $check = app(\Modules\MedBloodBank\Services\BloodBankService::class)->eligibility($donor);

                    return $check['eligible']
                        ? '<span class="label label-success">' . __('medbloodbank::lang.eligible') . '</span>'
                        : '<span class="label label-warning" title="' . e($check['reason']) . '">' . __('medbloodbank::lang.ineligible') . '</span>';
                })
                ->addColumn('action', function ($r) {
                    return '<button class="btn btn-xs btn-default mbb-modal-btn" data-href="'
                        . route('mbb.donors.edit', $r->id) . '"><i class="fa fa-edit"></i> ' . __('messages.edit') . '</button> '
                        . '<button class="btn btn-xs btn-danger mbb-delete-btn" data-href="'
                        . route('mbb.donors.destroy', $r->id) . '"><i class="fa fa-trash"></i></button>';
                })
                ->rawColumns(['donor_name', 'eligibility', 'action'])
                ->make(true);
        }

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

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

        return view('medbloodbank::donors.form', [
            'donor'       => new MbbDonor(),
            'bloodGroups' => MbbDonor::BLOOD_GROUPS,
            'contactName' => null,
        ]);
    }

    public function edit($id)
    {
        $this->guard('mbb.donors.manage');

        $donor = MbbDonor::forBusiness($this->businessId())->findOrFail($id);

        return view('medbloodbank::donors.form', [
            'donor'       => $donor,
            'bloodGroups' => MbbDonor::BLOOD_GROUPS,
            'contactName' => $donor->display_name,
        ]);
    }

    public function store(Request $request)
    {
        $this->guard('mbb.donors.manage');
        $data = $this->validated($request, false);

        try {
            // Enforce the "one donor per contact per business" satellite rule.
            $exists = MbbDonor::forBusiness($this->businessId())
                ->where('contact_id', $data['contact_id'])
                ->exists();
            if ($exists) {
                return $this->fail(__('medbloodbank::lang.donor_exists'));
            }

            $data['business_id'] = $this->businessId();
            MbbDonor::create($data);

            return $this->ok(__('medbloodbank::lang.donor_saved'));
        } catch (\Exception $e) {
            \Log::emergency($e->getMessage());

            return $this->fail();
        }
    }

    public function update(Request $request, $id)
    {
        $this->guard('mbb.donors.manage');
        $donor = MbbDonor::forBusiness($this->businessId())->findOrFail($id);
        $data = $this->validated($request, true);

        try {
            // contact_id is immutable on edit (the donor's identity).
            unset($data['contact_id']);
            $donor->update($data);

            return $this->ok(__('medbloodbank::lang.donor_saved'));
        } catch (\Exception $e) {
            \Log::emergency($e->getMessage());

            return $this->fail();
        }
    }

    public function destroy($id)
    {
        $this->guard('mbb.donors.manage');

        try {
            $donor = MbbDonor::forBusiness($this->businessId())->findOrFail($id);
            if ($donor->donations()->exists()) {
                return $this->fail(__('medbloodbank::lang.donor_in_use'));
            }
            $donor->delete();

            return $this->ok(__('medbloodbank::lang.donor_deleted'));
        } catch (\Exception $e) {
            return $this->fail();
        }
    }

    /**
     * Contact picker for the donor form. Searches ERP contacts (type customer /
     * both) in this business — a donor is a contact, not a parallel table.
     * Mirrors ClinicCore's clinic.patient-contacts.search.
     */
    public function search(Request $request)
    {
        $this->guard('mbb.donors.manage');

        $term = $request->input('q', '');

        $contacts = Contact::where('business_id', $this->businessId())
            ->whereIn('type', ['customer', 'both'])
            ->where('contact_status', 'active')
            ->where(function ($q) use ($term) {
                $q->where('name', 'LIKE', '%' . $term . '%')
                  ->orWhere('mobile', 'LIKE', '%' . $term . '%')
                  ->orWhere('email', 'LIKE', '%' . $term . '%')
                  ->orWhere('supplier_business_name', 'LIKE', '%' . $term . '%');
            })
            ->limit(20)
            ->get(['id', 'name', 'supplier_business_name', 'mobile', 'email']);

        return response()->json($contacts->map(function ($c) {
            $displayName = trim($c->name ?? '') ?: trim($c->supplier_business_name ?? '');

            return [
                'id'   => $c->id,
                'text' => $displayName . ($c->mobile ? ' (' . $c->mobile . ')' : ''),
            ];
        }));
    }

    private function validated(Request $request, bool $isEdit): array
    {
        $rules = [
            'contact_id'      => 'required|integer',
            'blood_group'     => 'nullable|in:' . implode(',', MbbDonor::BLOOD_GROUPS),
            'deferred_until'  => 'nullable|date',
            'deferral_reason' => 'nullable|string|max:255',
            'notes'           => 'nullable|string',
        ];
        if ($isEdit) {
            $rules['contact_id'] = 'nullable|integer';
        }

        $data = $this->validate($request, $rules);

        return [
            'contact_id'      => isset($data['contact_id']) ? (int) $data['contact_id'] : null,
            'blood_group'     => $data['blood_group'] ?? null,
            'deferred_until'  => $data['deferred_until'] ?? null,
            'deferral_reason' => $data['deferral_reason'] ?? null,
            'notes'           => $data['notes'] ?? null,
        ];
    }
}
