<?php

namespace App\Http\Controllers;
use App\Helpers\Helpers;
use App\Enums\RecordStatusEnum;
use App\Enums\UtilEnum;
use App\Http\Controllers\Helper\GlobalController;
use App\Http\Requests\SampleCreateRequest;
use App\Http\Requests\SampleDetailCreateRequest;
use App\Http\Requests\UpdateRequests\SampleUpdateRequest;
use App\Http\Resources\SampleResource;
use App\Models\AntibioticResult;
use App\Models\BaseModel;
use App\Models\OrganismResult;
use App\Models\Patient;
use App\Models\Physician;
use App\Models\RejectComment;
use App\Models\Sample;
use App\Models\SampleDetail;
use App\Models\SampleSource;
use App\Models\TestGroup;
use App\Models\TestResult;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Str;

use Telegram\Bot\Api;

use App\Models\Invoice;
use App\Models\InvoiceDetail;

use App\Models\LabConfigure;

class SampleController extends Controller
{

    protected $model;
    protected $physicianModel;
    protected $sampleSourceModel;
    protected $patientModel;
    protected $rejectCommentModel;
    protected $sampleDetailModel;
    protected $testResultModel;
    protected $testGroupModel;
    protected $organismResultModel;
    protected $antibioticResultModel;

    protected $baseLabId;
    protected $base;

    protected $invoiceModel;
    protected $invoiceDetailModel;
    protected $laboratoryConfigures;

    public function __construct(Sample $sampleModel, Physician $physicianModel, RejectComment $rejectCommentModel, TestGroup $testGroupModel,
                                SampleSource $sampleSourceModel, Patient $patientModel, SampleDetail $sampleDetailModel, TestResult $testResultModel,
                                OrganismResult $organismResultModel, AntibioticResult $antibioticResultModel, Invoice $invoiceModel, InvoiceDetail $invoiceDetailModel, LabConfigure $laboratoryConfigures
    ){
        $this->model = $sampleModel;
        $this->physicianModel = $physicianModel;
        $this->sampleSourceModel = $sampleSourceModel;
        $this->patientModel = $patientModel;
        $this->rejectCommentModel = $rejectCommentModel;
        $this->sampleDetailModel = $sampleDetailModel;
        $this->testResultModel = $testResultModel;
        $this->testGroupModel = $testGroupModel;
        $this->organismResultModel = $organismResultModel;
        $this->antibioticResultModel = $antibioticResultModel;

        $this->invoiceModel = $invoiceModel;
        $this->invoiceDetailModel = $invoiceDetailModel;
        $this->laboratoryConfigures = $laboratoryConfigures;

        $this->baseLabId = Session::get('base_lab_id');
        $this->base = Session::get('base_lab');
    }

    public function index(Request $request){
        if(!GlobalController::user_can(Auth::user()->role_id, ['view_sample'])) return redirect(url('my-profile'));
        $recordStatusConditions = Auth::id()==1 ? [RecordStatusEnum::ACTIVE, RecordStatusEnum::DELETE] : [RecordStatusEnum::ACTIVE];
        $samples = $this->model::with(['patient','sample_source'])
            ->whereIn(BaseModel::RECORD_STATUS_FIELD, $recordStatusConditions)
            ->where('lab_id', $this->baseLabId)
            ->when(Auth::user()->role_id == UtilEnum::PHYSICIAN_ROLE, function($sample){
                $sample->where('sample_source_id', Auth::user()->sample_source_id);
            })->when(!empty(trim($request->kword)), function ($samples) use($request, $recordStatusConditions){
                $samples->whereRaw("replace(sample_number, ' ','') like '%".str_replace(" ","",$request->kword)."%'")
                ->orWhereIn('patient_id', $this->patientModel::query()
                    ->whereRaw("replace(name_en, ' ','') like '%".str_replace(" ","",$request->kword)."%'")
                    ->orWhereRaw("replace(phone_number, ' ','') like '%".str_replace(" ","",$request->kword)."%'")
                    ->orWhere('patient_uuid','like','%'.$request->kword.'%')->pluck('id')->toArray()
                )->where('lab_id', $this->baseLabId)->whereIn(BaseModel::RECORD_STATUS_FIELD, $recordStatusConditions);
            })->when(!empty(trim($request->sample_status)), function ($samples) use($request){
                $samples->whereIn('id', $this->filterSampleStatus($request->sample_status));
            })->when(!empty($request->sample_date) && empty($request->kword) , function ($samples) use($request){
                $samples->whereDate('admission_date', date('Y-m-d',strtotime($request->sample_date)));
            })->orderBy(BaseModel::CREATED_AT_FIELD,'desc')->paginate(config('labis.pagination.perpage', 10));
        return view('sample', ['samples' => $samples]);
    }

    function filterSampleStatus($statusId){
        if($statusId == 5){ // rejected
            $wheres = " and sample.`sample_condition` = 0 ";
        }elseif ($statusId == 4){ // printed
            $wheres = " and (sample.`sample_condition` <>0 and sample.`is_printed` = 1) ";
        }elseif ($statusId == 1){ // pending, not request test, no result input
            $wheres = "  and (sample.`sample_condition` <>0 and sample.`is_printed` = 0 and (non_heading_tests=0 or (done_numeric_tests+done_org_test)=0)) ";
        }elseif ($statusId == 3){
            $wheres = " and (sample.`sample_condition` <>0 and sample.`is_printed` = 0 and non_heading_tests>0 and non_heading_tests = (done_numeric_tests+done_org_test))";
        }elseif ($statusId ==2 ){
            $wheres = " and (sample.`sample_condition` <>0 and sample.`is_printed` = 0 and (done_numeric_tests+done_org_test)>0 and non_heading_tests > (done_numeric_tests+done_org_test))";
        } else{
            $wheres = "";
        }

        $resultItemsData = DB::select('SELECT
                                            *
                                            FROM
                                            (
                                                SELECT
                                                s.id,
                                                s.`sample_number`,
                                                IFNULL(sample_condition,1) AS sample_condition,
                                                is_printed,
                                                SUM(IF(ts.`field_type`>0, 1,0)) AS non_heading_tests,
                                                SUM(IF(ts.`field_type` IN(1,4) AND tr.test_result IS NOT NULL, 1, 0)) AS done_numeric_tests,
                                                SUM(IF(ts.`field_type` IN(2,3) AND org_result.total_org_result>0, 1, 0)) AS done_org_test
                                                FROM samples s
                                                LEFT JOIN test_results tr
                                                ON tr.`sample_id` = s.`id`
                                                AND s.`lab_id` = tr.`lab_id`
                                                LEFT JOIN test_samples ts
                                                ON ts.id = tr.`test_sample_id`
                                                AND ts.lab_id = tr.lab_id
                                                LEFT JOIN sample_types st
                                                ON st.id = ts.`sample_type_id`
                                                LEFT JOIN(
                                                SELECT
                                                    tr.`id`,
                                                    COUNT(*) AS total_org_result
                                                FROM samples s
                                                INNER JOIN test_results tr
                                                ON tr.`sample_id` = s.`id`
                                                AND s.`lab_id` = tr.`lab_id`
                                                INNER JOIN organism_results orgr
                                                ON orgr.`test_result_id` = tr.`id`
                                                WHERE s.lab_id = '.$this->baseLabId.'
                                                AND tr.`record_status_id` = 1
                                                AND orgr.`record_status_id` = 1
                                                GROUP BY tr.id
                                                ) AS org_result
                                                ON org_result.id = tr.`id`
                                                WHERE s.`lab_id` = '.$this->baseLabId.'
                                                AND s.`record_status_id` = 1
                                                AND (tr.`record_status_id` = 1 OR tr.`record_status_id` IS NULL)
                                                AND (st.`record_status_id` = 1 OR st.`record_status_id` IS NULL)
                                                GROUP BY s.id, s.`sample_number`, s.sample_condition, s.is_printed
                                            ) sample
                                            WHERE 1 '.$wheres.'

                                            ');
        $arr = [];
        foreach ($resultItemsData as $row){
            $arr[] = $row->id;
        }
        return $arr;
    }

    public function create($patient_id = null){
        if(!GlobalController::user_can(Auth::user()->role_id, ['create_sample'])) return redirect(url('my-profile'));
        $rejectComments = $this->rejectCommentModel::query()->where([BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE])->orderBy('reject_comment', 'ASC')->get();
        $physicians = $this->physicianModel::query()->where([BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE, 'lab_id' => $this->baseLabId])->orderBy('name_en', 'ASC')->get();
        $sampleSources = $this->sampleSourceModel::query()->where([BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE, 'lab_id' => $this->baseLabId])->orderBy('name_en','ASC')->get();
        $patients = $this->patientModel::query()->where([BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE, 'lab_id' => $this->baseLabId])
            ->when(!empty($patient_id), function ($patients) use ($patient_id){
                $patients->where(['id' => $patient_id, 'lab_id' => $this->baseLabId ]);
            })->orderBy(BaseModel::CREATED_AT_FIELD, 'DESC')->limit(30)->get();
        $testGroups = $this->testGroupModel::with(['testGroupDetails'])->where(['lab_id' => $this->baseLabId, BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE])->orderBy('created_at')->get();
        return view('new_sample', [
            'labSettings' => (object) $this->base,
            'physicians' => $physicians,
            'sampleSources' => $sampleSources,
            'patients' => $patients,
            'rejectComments' => $rejectComments,
            'provinces' => $this->province(),
            'patient_id' => $patient_id,
            'testGroups' => $testGroups
        ]);
    }

    public function generateAutoId($admissionDate){
        $prefix = date('ymd',strtotime($admissionDate));
        $sample = Sample::query();
        $sampleCount = $sample->where('lab_id', $this->baseLabId)->whereRaw('date(admission_date) ="'. date('Y-m-d',strtotime($admissionDate)).'"')->count();
        return 'S-'.$this->base['short_name'].'-'.$prefix.'-'.(str_pad(($sampleCount+1),3,'0',STR_PAD_LEFT));
    }

    public function store(SampleCreateRequest $sampleCreateRequest){
        DB::beginTransaction();
        try{
            if(!GlobalController::user_can(Auth::user()->role_id, ['create_sample'])) return false;
            $request = collect($sampleCreateRequest)->merge(['lab_id'=>$this->baseLabId]);
            if(empty($sampleCreateRequest->sample_number)) {
                $sampleNumber = $this->generateAutoId($sampleCreateRequest->admission_date);
                $request = $request->merge(['sample_number' => $sampleNumber]);
            }

            $sample = $this->model::query()->where(['sample_number' => $request['sample_number']])->get()->first();
            if(!empty($sample)){
                if($sample->patient_id !=$request['patient_id']){
                    if(empty($sampleCreateRequest->sample_number)) {
                        sleep(50);
                        $sampleNumber = $this->generateAutoId($sampleCreateRequest->admission_date);
                        $request = $request->merge(['sample_number' => $sampleNumber]);
                    }
                    else{
                        return response()->json(['success' => false, 'message' => __('comment.create_fail'), 'errors' => ['Duplicate Sample Number']]);
                    }
                    $patientSample = $this->model::query()->create($request->all());
                    $patientSample = $this->model::with(['patient','sample_source'])->find($patientSample->id);
                }
                else{
                    $patientSample = $this->model::with(['patient','sample_source'])->find($sample->id);
                }
            }
            else{
                $patientSample = $this->model::query()->create($request->all());
                $patientSample = $this->model::with(['patient','sample_source','physician'])->find($patientSample->id);
            }

            DB::commit();
            return response()->json(['success' => true, 'message' => __('sample.create_success'), 'data' => new SampleResource($patientSample)]);
        } catch (\Exception $e){
            DB::rollBack();
            return response()->json(['success' => false, 'message' => __('comment.create_fail'), 'errors' => [$e->getMessage()]]);
        }
    }

    public function store1(SampleCreateRequest $sampleCreateRequest){
        DB::beginTransaction();
        try{
            $request = collect($sampleCreateRequest)->merge(['lab_id'=>$this->baseLabId]);
            if(empty($sampleCreateRequest->sample_number)) {
				$sampleNumber = $this->generateAutoId($sampleCreateRequest->admission_date);
                $request = $request->merge(['sample_number' => $sampleNumber]);
            }
            $patientSample = $this->model::query()->create($request->all());
            $patientSample = $this->model::with(['patient','sample_source'])->find($patientSample->id);
            DB::commit();
            return response()->json(['success' => true, 'message' => __('sample.create_success'), 'data' => new SampleResource($patientSample)]);
        } catch (\Exception $e){
            DB::rollBack();
            return response()->json(['success' => false, 'message' => __('comment.create_fail'), 'errors' => [$e->getMessage()]]);
        }
    }

    public function edit(Request $request, $id){ // url: base_url/sample/edit/[sample-id]
        if(!GlobalController::user_can(Auth::user()->role_id, ['update_sample'])) return redirect(url('my-profile'));
        $sample = $this->model::with(['patient'/*'patient.telegramChatId'*/,'invoice'])->where(['lab_id' => $this->baseLabId,'id' => $id])->first();
        $rejectComments = $this->rejectCommentModel::query()->where([BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE])->orderBy('reject_comment', 'ASC')->get();
        $physicians = $this->physicianModel::query()->where([BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE, 'lab_id' => $this->baseLabId])->orderBy('name_en', 'ASC')->get();
        $samplePhysician = $this->physicianModel::query()->where('id', $sample->physician_id)->first();
        $sampleSources = $this->sampleSourceModel::query()->where([BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE, 'lab_id' => $this->baseLabId])->orderBy('name_en','ASC')->get();
        $testGroups = $this->testGroupModel::with(['testGroupDetails'])->where(['lab_id' => $this->baseLabId, BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE])->orderBy('created_at')->get();

        $now = strtotime($sample->admission_date); // or your date as well
        $your_date = strtotime($sample->patient->dob);
        $datediff = $now - $your_date;

        $form = $sample->sample_tests->pluck('testSample')->pluck('sample')->unique()->first();

        $enter_form_id = $form->enter_form_id ?? ($this->base['lab_category_id']==0? 1:2);
        $preview_form_id = $form->preview_form_id ?? ($this->base['lab_category_id']==0? 1:2);

        $prevSample = [];
        if(isset($_GET['previous_sample'])){
            $prevSample = $this->model::with(['patient','invoice'])->where(['lab_id' => $this->baseLabId, 'id' => $_GET['previous_sample']])->get();
        }

        $labConfigures = $this->laboratoryConfigures::query()->where(['lab_id' => $this->baseLabId, BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE])->get()->toArray();

        $resultTemplateId = (collect($labConfigures)->where('atrribute_code', 'RESULT_TEMPLATE')->pluck('assigned_attribute_value')->first());
        if(!empty($resultTemplateId)){
            $preview_form_id = $resultTemplateId;
        }

        if($sample->result_template_id > 0){
            $preview_form_id = $sample->result_template_id;
        }

        return view('sample_edition', [
            'sample' => $sample,
            'labSettings' => (object) $this->base,
            'physicians' => $physicians,
            'sampleSources' => $sampleSources,
            'rejectComments' => $rejectComments,
            'testGroups' => $testGroups,
            'samplePhysician' => $samplePhysician,
            'agedy' => number_format((round($datediff / (60 * 60 * 24))/360),2),
            'enter_form_id' => $enter_form_id, // $form->enter_form_id ?? 1,
            'preview_form_id' => $preview_form_id . (isset($request->previous_sample) ? '_previous_sample':''),
            'previous_samples' => $this->getPreviousSample($sample->patient_id, $id),
            'labConfigures' => $labConfigures,
            'prevSample' => $prevSample,
            'firstPrvSampleId' => (int)@$this->getPreviousSample($sample->patient_id, $id)->first()->id,
            'firstPrvSampleDate' => (string) !empty($this->getPreviousSample($sample->patient_id, $id)->first()) ? date('d-m-Y', strtotime($this->getPreviousSample($sample->patient_id, $id)->first()->admission_date)) : '',
            'selected_pre_sample_date' => isset($request->previous_sample) ? date('d-m-Y', strtotime($this->getPreviousSample($sample->patient_id, $id)->where('id', $request->previous_sample)->first()->admission_date)) : ''
        ]);


    }

    function getPreviousSample($patientId, $curSampleId){
        return $this->model::query()->where(['patient_id' => $patientId, 'lab_id' => $this->baseLabId, BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE])
            ->where('id','<', $curSampleId)->orderBy('id', 'desc')->get(['id','admission_date', 'sample_number']);
    }

    /** Update Sample Only
     * @param SampleUpdateRequest $sampleUpdateRequest
     * @return \Illuminate\Http\RedirectResponse
     */

    public function update(SampleUpdateRequest $sampleUpdateRequest){
        DB::beginTransaction();
        try{
            if(!GlobalController::user_can(Auth::user()->role_id, ['update_sample'])) return redirect(url('my-profile'));
            $request = collect($sampleUpdateRequest)->except(['id','sample_number','patient_id','_token']);
            $patientSample = $this->model::query()->where(['id' => $sampleUpdateRequest->id, 'lab_id' => $this->baseLabId])->first();
            $patientSample->update($request->all());
            DB::commit();
            $sampleUpdateRequest->session()->flash('message','Update success.');
            return redirect()->back();
        } catch (\Exception $e){
            if(Auth::id()==1){
            dd($e);
            }
            DB::rollBack();
            $sampleUpdateRequest->session()->flash('message','Update failed.');
            return redirect()->back();
        }
    }

    /** Perform by ajax function */

    public function delete(Request $request){
        try{
            if(!GlobalController::user_can(Auth::user()->role_id, ['delete_sample'])) return false;
            $patientSample = $this->model::query()->where(['id' => $request->uid, 'lab_id' => $this->baseLabId])->first();
            $patientSample->update(array(BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::DELETE));
            return response()->json(['success' => true, 'message' => __('sample.delete_success')]);
        }
        catch (\Exception $e){
            return response()->json(['success' => false, 'message' => __('sample.delete_fail'), 'errors' => $e->getMessage()]);
        }
    }

    public function restore(Request $request){
        try{
            $patientSample = $this->model::query()->where(['id' => $request->uid, 'lab_id' => $this->baseLabId])->first();
            $patientSample->update(array(BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE));
            return response()->json(['success' => true, 'message' => __('sample.restore_success')]);
        }
        catch (\Exception $e){
            return response()->json(['success' => false, 'message' => __('sample.restore_fail'), 'errors' => $e->getMessage()]);
        }
    }

    public function approve(Request $request){
        try{
            if(!GlobalController::user_can(Auth::user()->role_id, ['approve_result'])) return false;
            $patientSample = $this->model::query()->where(['id' => $request->uid, 'lab_id' => $this->baseLabId])->first();
            $patientSample->update(array('approved_by' => Auth::id(), 'approved_date' => date('Y-m-d H:i:s')));
            return response()->json(['success' => true, 'message' => __('sample.approve_success')]);
        }
        catch (\Exception $e){
            return response()->json(['success' => false, 'message' => __('sample.approve_fail'), 'errors' => $e->getMessage()]);
        }
    }

    /** Sample Detail / Assign Test */

    public function storeSampleDetail(SampleDetailCreateRequest $sampleCreateRequest){
        set_time_limit(6000);
        ini_set('memory_limit', '10240M');
        DB::beginTransaction();
        try{
            if(!GlobalController::user_can(Auth::user()->role_id, ['create_sample', 'update_sample'])) return false;
            $this->sampleDetailModel::query()->where(['sample_id' => $sampleCreateRequest->sample_id, 'lab_id' => $this->baseLabId])->update(array(BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::DELETE));
            $sampleDetails = collect($sampleCreateRequest->sample_details);
            $sampleDetails->map(function ($item){
                if(!empty($item['sample_description'])){
                    $sampleDetail = $this->sampleDetailModel::query()->create([
                        'sample_id' => $item['sample_id'],
                        'sample_type_id' => $item['sample_type_id'],
                        'test_date' => date('Y-m-d'),
                        'lab_technician_id' => Auth::id(),
                        'sample_descr' => $item['sample_description'],
                        'lab_id' => $this->baseLabId
                    ]);
                }
            });
            //dd($sampleCreateRequest->sample_tests);
            if(!empty($sampleCreateRequest->sample_tests)){
                $this->testResultModel::query()->where(['sample_id' => $sampleCreateRequest->sample_id, 'lab_id' => $this->baseLabId])
                    ->whereNotIn('test_sample_id', $sampleCreateRequest->sample_tests)
                    ->delete();
                foreach ($sampleCreateRequest->sample_tests as $test){
                    $existingTestResult = $this->testResultModel::query()->where([
                        'test_sample_id' => $test,
                        'lab_id' => $this->baseLabId,
                        'sample_id' =>  $sampleCreateRequest->sample_id
                    ])->get()->toArray();
                    if(empty($existingTestResult)) {
                        $testResult = $this->testResultModel::query()->create([
                            'sample_id' => $sampleCreateRequest->sample_id,
                            'test_sample_id' => $test,
                            'lab_id' => $this->baseLabId
                        ]);
                    }
                }
            }else{
                $this->testResultModel::query()->where(['sample_id' => $sampleCreateRequest->sample_id, 'lab_id' => $this->baseLabId])->delete();
            }


             /**
             * Create or Update Invoice in case invoice generation mode is auto start
             */

            $labSettings = (object) $this->base;
            if($labSettings->is_auto_make_invoice == 1) {
                $sample = $this->model::with('invoice')->find($sampleCreateRequest->sample_id);
                $invoiceDetail = $this->makeInvoice($sample->id);

                $request = new Request($invoiceDetail);
                $summary = collect($request);

                $total = $summary->sum('usd_price');
                $grossTotal = $summary->sum('item_discount'); // total price after discount
                $discount = $total - $grossTotal;
                $invoiceId = 0;
                $discounts = $summary->sum('discount_price');
                if (empty($sample->invoice)) {
                    // create new
                    $invoiceRequest = collect($request)->merge([
                        'invoice_code' => $this->generateInvoiceId(date('Y-m-d', strtotime($sample->admission_date))),// 'I-'.Helpers::generateUuId($labSettings->short_name),
                        'sample_id' => $sample->id,
                        'total' => $total * ($labSettings->currency==1 ? $labSettings->exchange_rate : 1),
                        'discount' => $discounts * ($labSettings->currency==1 ? $labSettings->exchange_rate : 1),
                        'discount_type' => $labSettings->discount_type,
                        'gross_total' => number_format($grossTotal * ($labSettings->currency==1 ? $labSettings->exchange_rate : 1),2,  '.', ''),
                        'deposit' => 0,
                        'bank_deposit' => 0,
                        'balance' => number_format($grossTotal * ($labSettings->currency==1 ? $labSettings->exchange_rate : 1),2,  '.', ''),
                        'invoice_date' => date('Y-m-d', strtotime($sample->admission_date)),
                        'lab_id'=>$this->baseLabId,
                        'exchange_rate' => $labSettings->exchange_rate
                    ]);
                    $invoice = $this->invoiceModel::query()->create($invoiceRequest->all());
                    $invoiceId = $invoice->id;
                }
                else {
                    $invoiceId = $sample->invoice->id;
                    $editInvoice = $this->invoiceModel::query()->find($sample->invoice->id);
                    $deposit = $editInvoice->deposit;
                    $bank_deposit = $editInvoice->bank_deposit;
                    $editInvoice->total = $total * ($labSettings->currency==1 ? $labSettings->exchange_rate : 1);
                    $editInvoice->discount = $discounts * ($labSettings->currency==1 ? $labSettings->exchange_rate : 1);
                    $editInvoice->gross_total = number_format($grossTotal * ($labSettings->currency==1 ? $labSettings->exchange_rate : 1),2, '.', '');
                    $editInvoice->balance = number_format(($grossTotal-($deposit+$bank_deposit)),2, '.', '');
                    $editInvoice->save();
                    $this->invoiceDetailModel::query()->where('invoice_id', $sample->invoice->id)->delete();
                }
                // Refresh Invoice Detail
                $invoiceDetailRequest = collect($invoiceDetail);
                $items = $invoiceDetailRequest->map(function ($row) use($invoiceId, $labSettings) {
                    $invoiceDetailRow = $this->invoiceDetailModel::query()->create([
                        'invoice_id' => $invoiceId,
                        'test_sample_id' => $row['test_sample_id'],
                        'discount_type' => $row['item_discount_type'],
                        'discount' => $row['item_discount'],
                        'test_name' => $row['group_result'],
                        'qty' => 1,
                        'unit_price' =>  $row['usd_price'] * ($labSettings->currency==1 ? $labSettings->exchange_rate : 1),
                    ]);
                    return [];
                });
            }

            /**
             * Create or Update Invoice in case invoice generation mode is auto end
             */

            DB::commit();
            return response()->json(['success' => true, 'message' => __('sample.assign_tests_success')]);
        } catch (\Exception $e){
            Log::error($e);
            DB::rollBack();
            return response()->json(['success'=> false , 'errors' => [$e->getMessage()]]);
        }
    }

    public function storeSampleTestResult(Request $request){
        set_time_limit(6000);
        ini_set('memory_limit', '10240M');
        if(!GlobalController::user_can(Auth::user()->role_id, ['add_result', 'update_result', 'delete_result'])) return false;
        $validator = \Validator::make($request->all(), ['sample_id' => 'required', 'ref_test_sample_id' => 'nullable', 'ref_test_sample_id_value' => 'nullable', 'test_samples_to_hide' => 'nullable', 'ref_test_sample_performer' => 'nullable']);
        if ($validator->fails()) {return response()->json(['errors'=>$validator->errors()->all()]);}
        DB::beginTransaction();
        try{
            $sample = $this->model::query()->find($request->sample_id);
            $sample->update([
                BaseModel::UPDATED_AT_FIELD => date('Y-m-d H:i:s'),
                BaseModel::UPDATED_BY_FIELD => Auth::id()
            ]);
            // add test result
            if(isset($request->ref_test_sample_id)){
                $data = collect($request->ref_test_sample_id);
                $ref_test_sample_id_value = collect($request->ref_test_sample_id_value);
                $ref_test_date = collect($request->ref_test_sample_test_date);
                $ref_performed_by = collect($request->ref_test_sample_performer);
                $ref_test_sample_comment = collect($request->ref_test_sample_comment);
                $vars = $data->map(function ($val, $key) use($request, $ref_test_sample_id_value, $ref_test_date, $ref_performed_by, $ref_test_sample_comment){
                    $this->testResultModel::query()->where(['lab_id' => $this->baseLabId, 'sample_id' => $request->sample_id, 'test_sample_id' => $val])->update([
                        'test_result' => @$ref_test_sample_id_value[$key],
                        'test_date' => @$ref_test_date[$key],
                        'performed_by' => @$ref_performed_by[$key],
                        'comment' => $ref_test_sample_comment[$key],
                    ]);
                });
            }


            if(isset($request->ref_test_sample_id___)){
                $datas = collect($request->ref_test_sample_id___);
                //$ref_test_date = collect($request->ref_test_sample_test_date);
                //$ref_performed_by = collect($request->ref_test_sample_performer);
                $ref_test_sample_comment_ = collect($request->ref_test_sample_comment___);
                $vars = $datas->map(function ($val_, $key_) use($request, $ref_test_sample_comment_){
                    $this->testResultModel::query()->where(['lab_id' => $this->baseLabId, 'sample_id' => $request->sample_id, 'test_sample_id' => $val_])->update([
                        //'test_date' => @$ref_test_date[$key],
                        //'performed_by' => @$ref_performed_by[$key],
                        'comment' => $ref_test_sample_comment_[$key_],
                    ]);
                });
            }

            // set hide test

            if(isset($request->test_samples_to_hide)){
                $this->testResultModel::query()->where(['lab_id' => $this->baseLabId, 'sample_id' => $request->sample_id])
                    ->whereNotIn('test_sample_id', $request->test_samples_to_hide)->update(['is_show' => 1]);

                foreach ($request->test_samples_to_hide as $val){
                    $this->testResultModel::query()->where(['lab_id' => $this->baseLabId, 'sample_id' => $request->sample_id, 'test_sample_id' => $val])->update([
                        'is_show' => 0
                    ]);
                }
            } else{
                $this->testResultModel::query()->where(['lab_id' => $this->baseLabId, 'sample_id' => $request->sample_id])->update(['is_show' => 1]);
            }

            // organism result
            if(isset($request->possible_result)){
                $possible_results = collect(json_decode($request->possible_result))->flatten(1);
                //$organismIds = $possible_results->pluck('organism_id')->toArray();
                foreach ($possible_results as $k=>$org){

                    $organismIds = $possible_results->filter(function($item) use($org){
                        return $item->test_sample_id == $org->test_sample_id;
                    })->pluck('organism_id')->toArray();

                    // change on 08/Sep/2023 to fixed issue save result success but no data affect
                    //$testResult = $this->testResultModel::query()->where(['test_sample_id' => $org->test_sample_id, BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE])->orderByDesc('id')->limit(1)->first();
                    $testResult = $this->testResultModel::query()->where(['test_sample_id' => $org->test_sample_id, BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE, 'lab_id' => $this->baseLabId, 'sample_id' => $request->sample_id])->orderByDesc('id')->limit(1)->first();

                    if(count($organismIds)>0){
                        $this->organismResultModel::query()->where(['test_result_id' => $testResult->id, 'lab_id' => $this->baseLabId])->whereNotIn('organism_id', $organismIds)->update(['record_status_id' => 0]);
                    }

                    $organismResult = $this->organismResultModel::query()->where(['test_result_id' => $testResult->id, 'organism_id' => $org->organism_id, BaseModel::RECORD_STATUS_FIELD =>RecordStatusEnum::ACTIVE, 'lab_id' => $this->baseLabId])->first();
                    //$organismResultId = 0;

                    if(!empty($organismResult)){
                        $organismResultId = $organismResult->id;
                        $this->organismResultModel::query()->find($organismResult->id)->update([
                            'quantity_id' => (int)$org->quantity_id,
                            'contaminant' => $org->contaminant
                        ]);
                    }
                    else{
                        $savedOrg = $this->organismResultModel::query()->create([
                            'test_result_id' => $testResult->id,
                            'organism_id' => $org->organism_id,
                            'quantity_id' => (int)$org->quantity_id,
                            'contaminant' => $org->contaminant,
                            'lab_id' => $this->baseLabId,
                            BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE,
                            BaseModel::CREATED_AT => date('Y-m-d H:i:s')
                        ]);
                        $organismResultId = $savedOrg->id;
                    }


                    if(isset($request->anti_result)){
                        $anti_result = collect(json_decode($request->anti_result))->flatten(1);
                        if(in_array($org->test_organism_id, $anti_result->pluck('test_organism_id')->unique()->flatten(1)->toArray())){
                            $this->antibioticResultModel::query()->where('organism_result_id', $organismResultId)->delete();
                        }
                        foreach ($anti_result as $j=>$anti){
                            if($anti->test_organism_id == $org->test_organism_id && $anti->sensitive !="") {
                                $this->antibioticResultModel::query()->updateOrCreate([
                                    'organism_result_id' => $organismResultId,
                                    'antibiotic_id' => $anti->antibiotic_id
                                ], [
                                    'organism_result_id' => $organismResultId,
                                    'antibiotic_id' => $anti->antibiotic_id,
                                    'disk_diffusion' => $anti->disk_diffusion,
                                    'mic' => $anti->mic,
                                    'sensitive' => $anti->sensitive,
                                    'is_hide' => $anti->is_hide,
                                    BaseModel::CREATED_AT_FIELD => date('Y-m-d H:i:s'),
                                    BaseModel::CREATED_BY_FIELD => Auth::id(),
                                    BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE
                                ]);
                            }
                        }
                    }

                }
            }
            DB::commit();
            return response()->json(['success'=> true , 'message' => 'Sample result already saved.']);
        } catch (\Exception $e){
            DB::rollBack();
            Log::error($e);
            return response()->json(['success'=> false , 'error' => 'Failed while update sample result.']);
        }
    }

    public function getSampleTest($sample_id){
        try{
            $sample = $this->model::with(['patient','sample_source','sample_details','sample_tests', 'physician'])->find($sample_id);
            return response()->json(['success'=> true , 'data' => new SampleResource($sample)]);
        } catch (\Exception $e){
            return response()->json(['success'=> false , 'message' => $e->getMessage()]);
        }
    }



    function makeInvoice($sampleId){
        try{
            $resultItems = DB::select('
                                            SELECT
                                                d.`id` AS department_id,
                                                d.`name_en` AS department_name,
                                                d.weight as dweight,
                                                st.`id` AS sample_type_id,
                                                st.weight as sweight,
                                                st.`name_en` AS sample_type,
                                                ts.`id` AS test_sample_id,
                                                ts.`heading_id` AS parent_id,
                                                ts.`field_type`,
                                                ts.`usd_price`,
                                                ts.group_result,
                                                ts.description,
                                                t.`id` AS test_id,
                                                t.`name_en` AS test_name,
						                        tr.id as test_result_id,
						                        pct.`commission_type`,
						                        ifnull(pct.`commission_rate`, 0.00) as commission_rate,
						                        ifnull(pct.`partner_price`, 0.00) as partner_price,
						                        ts.weight
                                            FROM samples s
                                            INNER JOIN test_results tr
                                            ON tr.`sample_id` = s.`id`
                                            AND s.`lab_id` = tr.`lab_id`
                                            INNER JOIN test_samples ts
                                            ON ts.id = tr.`test_sample_id`
                                            and ts.lab_id = tr.lab_id
                                            INNER JOIN tests t
                                            ON t.`id` = ts.`test_id`
                                            INNER JOIN sample_types st
                                            ON st.`id` = ts.`sample_type_id`
                                            INNER JOIN departments d
                                            ON d.`id` = st.`department_id`
                                            LEFT JOIN `physician_commisssion` AS pct
                                            ON pct.`test_sample_id` =  ts.`id`
                                            AND pct.`physician_id` = s.`physician_id`
                                            WHERE s.`id` = '.$sampleId.'
                                            AND s.`lab_id`= '.$this->baseLabId.'
                                            AND tr.`record_status_id` = '.BaseModel::RECORD_STATUS_ACTIVE.'
                                            AND LENGTH(ts.group_result)>0
                                            AND ts.usd_price>0
                                            ORDER BY
                                            d.`weight`,
                                            st.`weight`,
                                            ts.`weight`');
            $departmentArray = array();
            foreach ($resultItems as $row){
                $net_amount = number_format((((!empty($row->commission_type) ? $row->commission_type : ((object) $this->location())->discount_type)) ==2 ? (($row->usd_price - $row->partner_price) - $row->commission_rate) :
                    (($row->usd_price - $row->partner_price) * (1-$row->commission_rate/100))),3);
                $testItemArray = array(
                    'test_sample_id' => (string)$row->test_sample_id,
                    'test_id' => $row->test_id,
                    'test_name' => $row->test_name,
                    'closed_parent_id' => (string) (int)$row->parent_id,
                    'field_type' => (string) $row->field_type,
                    'usd_price' => $row->usd_price,
                    'group_result' => (string) $row->group_result,
                    'item_discount_type' => (!empty($row->commission_type) ? $row->commission_type : ((object) $this->location())->discount_type),
                    'item_discount_rate' => $row->commission_rate,
                    'item_discount' => $net_amount,
                    'discount_price' => ($row->usd_price - $net_amount)
                );
                $departmentArray[] = $testItemArray;
            }
            return $departmentArray;
        } catch (\Exception $e){
            return $e->getMessage();
        }
    }

    function printRecorder(Request $request){
        DB::beginTransaction();
        try{
            $patientSample = $this->model::query()->where(['id' => $request->uid, 'lab_id' => $this->baseLabId])->first();
            if($patientSample->is_printed==0) {
                $patientSample->update(
                    [
                        'is_printed' => 1,
                        'printed_at' => date('Y-m-d H:i:s'),
                        'printed_by' => Auth::id()
                    ]
                );
            }
            DB::commit();
            return response()->json(['success'=> true , 'data' => $patientSample]);
        } catch (\Exception $e){
            DB::rollBack();
            return response()->json(['success'=> false , 'errors' => [$e->getMessage()]]);
        }
    }

    public function generateInvoiceId($invoiceDate){
        $prefix = date('y',strtotime($invoiceDate));
        $invoiceCount = $this->invoiceModel::query()->where('lab_id', $this->baseLabId)->whereRaw('year(invoice_date) ="'. date('Y',strtotime($invoiceDate)).'"')->count();
        return 'I-'.$this->base['short_name'].'-'.$prefix.'-'.(str_pad(($invoiceCount+1),5,'0',STR_PAD_LEFT));
    }



    function temporarySaveOrganismResult($sampleId, $testSampleId, $organismId){
        // if(Auth::user()->id==1){
            DB::beginTransaction();
            try{
                $testResult = $this->testResultModel::query()->where(['test_sample_id' => $testSampleId, BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE, 'lab_id' => $this->baseLabId, 'sample_id' => $sampleId])->orderByDesc('id')->limit(1)->first();
                $organismResult = $this->organismResultModel::query()->where(['test_result_id' => $testResult->id, 'organism_id' => $organismId, BaseModel::RECORD_STATUS_FIELD =>RecordStatusEnum::ACTIVE, 'lab_id' => $this->baseLabId])->first();
                if(empty($organismResult)){

                    $savedOrg = $this->organismResultModel::query()->create([
                    'test_result_id' => $testResult->id,
                    'organism_id' => $organismId,
                    'quantity_id' => 0,
                    'contaminant' => 0,
                    'lab_id' => $this->baseLabId,
                    BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE,
                    BaseModel::CREATED_AT => date('Y-m-d H:i:s')
                    ]);
                }
                DB::commit();
                return response()->json(['success'=> true , 'message' => 'organisam_result_saved']);
            } catch (\Exception $e){
                DB::rollBack();
                return response()->json(['success'=> false , 'errors' => [$e->getMessage()]]);
            }

        //}

    }

    function temporarySaveOrganismResultQuantity($sampleId, $testSampleId, $organismId, $qtyId){
         //if(Auth::user()->id==1){
            DB::beginTransaction();
            try{
                $testResult = $this->testResultModel::query()->where(['test_sample_id' => $testSampleId, BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE, 'lab_id' => $this->baseLabId, 'sample_id' => $sampleId])->orderByDesc('id')->limit(1)->first();
                $organismResult = $this->organismResultModel::query()->where(['test_result_id' => $testResult->id, 'organism_id' => $organismId, BaseModel::RECORD_STATUS_FIELD =>RecordStatusEnum::ACTIVE, 'lab_id' => $this->baseLabId])->first();
                if(!empty($organismResult)){
                    $savedOrg = $this->organismResultModel::query()->where(['test_result_id' => $testResult->id, 'organism_id' => $organismId,  BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE, 'lab_id' => $this->baseLabId])
                    ->update([
                        'quantity_id' => $qtyId
                    ]);
                }
                DB::commit();
                return response()->json(['success'=> true , 'message' => 'organisam_result_saved_by_addmin']);
            } catch (\Exception $e){
                DB::rollBack();
                return response()->json(['success'=> false , 'errors' => [$e->getMessage()]]);
            }

        //}

    }

    public function uploadAttachmentResult(Request $request){
        try {
            $image = $request->file('image');
            $imageName = Str::uuid()->toString().'.' . $image->getClientOriginalExtension();
            $image->move(public_path('storage/images/attachment_lab_result'), $imageName);
            return response()->json(['success' => true, 'message' => __('laboratory.update_success'), 'data' => array('result' =>$imageName)]);
        }catch (\Exception $e){
            return response()->json(['success'=> false , 'message' => __('laboratory.update_fail'), 'errors' => $e->getMessage()]);
        }
    }

    function sendLabResultLink(Request $request, $patientId, $sampleId)
    {
        try {
            $telegram = new Api(env('TELEGRAM_BOT_TOKEN'));

            $sample = $this->model::with(['patient','sample_source','lab'])->where(['id' => $sampleId])->first();

            $text_message = "🧪 ".$sample->lab->name_en." Labo Result\n"
                    ."------------------------------------------------\n"
                    ."Patient Name:".$sample->patient->name_en."\n"
                    ."Age: ".Helpers::getAge($sample->patient->dob, $sample->admission_date)." (".Helpers::getGenderFull($sample->patient->gender).")\n"
                    ."Patients ID: ".$sample->patient->patient_uuid."\n"
                    ."Sample Source: ".$sample->sample_source->name_en."\n"
                    ."👉 <a href='https://vechsa.com/shared/lab-result/{$sampleId}'>Click To View Result</a>\n"
                    ."------------------------------------------------\n"
                    ."Date: ".date("D d/m/Y H:i");

            if($request->target_receiver=='patient'){
                $chat = DB::table('patient_telegram')->where('patient_id', $patientId)->first();
                if ($chat) {
                    $telegram->sendMessage([
                        'chat_id' => $chat->chat_id,
                        'text'    => $text_message,
                        'parse_mode' => 'HTML',

                    ]);
                }
            }
            else{
                $sample = $this->model::with(['sample_source.telegramChatId'])->find($sampleId);
                if(isset($sample->sample_source->telegramChatId) && !empty($sample->sample_source->telegramChatId)){
                    $telegram->sendMessage([
                        'chat_id' => $sample->sample_source->telegramChatId->chat_id,
                        'text'    => $text_message,
                        'parse_mode' => 'HTML',
                    ]);
                }
            }

            return response()->json(['success'=> true , 'message' => 'Laboroatory results have been sent!']);
        }catch (\Exception $e){
            return response()->json(['success'=> false , 'message' => 'Laboroatory results sent failed!']);
            //return response()->json(['success'=> false , 'message' => __('laboratory.update_fail'), 'errors' => $e->getMessage()]);
        }
    }

    public function updateSampleResultTemplate(Request $request){
        try{
            $patientSample = $this->model::query()->where(['id' => $request->uid, 'lab_id' => $this->baseLabId])->first();
            $patientSample->update(['result_template_id' => $request->result_template_id]);
            return response()->json(['success'=> true , 'message' => 'Sample result template already saved!']);
        } catch (\Exception $e){
            return response()->json(['success'=> false , 'message' => 'Failed while saving sample result template']);
        }
    }

}
