<?php

namespace App\Http\Controllers;
use App\Enums\RecordStatusEnum;
use App\Http\Controllers\Helper\GlobalController;
use App\Http\Requests\TestSampleCreateRequest;
use App\Http\Requests\UpdateRequests\TestSampleUpdateRequest;
use App\Http\Resources\TestSampleResource;
use App\Models\Antibiotic;
use App\Models\BaseModel;
use App\Models\Department;
use App\Models\Organism;
use App\Models\PatientType;
use App\Models\Physician;
use App\Models\PhysicianCommission;
use App\Models\SampleType;
use App\Models\Test;
use App\Models\TestCategory;
use App\Models\TestNormalValue;
use App\Models\TestSample;
use App\Models\TestSampleOrganism;
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 App\Models\Laboratory;

class TestController extends Controller
{

    protected $model;
    protected $departmentModel;
    protected $sampleTypeModel;
    protected $patientTypeModel;
    protected $testModel;
    protected $organismModel;
    protected $antibioticModel;
    protected $testSampleOrganismModel;
    protected $testSampleOrganismAntibioticModel;
    protected $testNormalValueModel;
    protected $physicianModel;
    protected $physicianCommissionModel;
    protected $labModel;

    protected $baseLabId;
    protected $labs;
    protected $base;
    protected $testCategoryModel;

    public function __construct(TestSample $testSample, Department $departmentModel, PhysicianCommission $physicianCommissionModel,
                                TestSampleOrganism $testSampleOrganismModel,SampleType $sampleTypeModel,
                                PatientType $patientTypeModel,Test $testModel, Organism $organismModel,
                                Antibiotic $antibioticModel,
                                TestNormalValue $testNormalValueModel, Physician $physicianModel, Laboratory $labModel
    ){
        $this->model = $testSample;
        $this->departmentModel = $departmentModel;
        $this->sampleTypeModel = $sampleTypeModel;
        $this->patientTypeModel = $patientTypeModel;
        $this->testModel = $testModel;
        $this->organismModel = $organismModel;
        $this->antibioticModel = $antibioticModel;
        $this->testSampleOrganismModel = $testSampleOrganismModel;
        $this->testNormalValueModel = $testNormalValueModel;
        $this->physicianModel = $physicianModel;
        $this->physicianCommissionModel = $physicianCommissionModel;
        $this->labModel = $labModel;
        $this->testCategoryModel = new TestCategory();

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

    public function index(Request $request){
        return null;
    }

    public function save(Request $request){
        try{
            $validator = \Validator::make($request->all(), ['name_en' => 'required']);
            if ($validator->fails()){ return response()->json(['errors'=>$validator->errors()->all()]);}
            $test  = $this->testModel::query()->create([
                'name_en' => $request->name_en,
                'lab_id' => $this->baseLabId,
            ]);
            return response()->json(['success'=> true , 'data' => [$test]]);
        } catch (\Exception $e)
        {
            return response()->json(['success'=> false , 'errors' => [$e->getMessage()]]);
        }
    }

    public function update(Request $request){
        try{
            $validator = \Validator::make($request->all(), ['uid' => 'required', 'name_en' => 'required']);
            if ($validator->fails()){ return response()->json(['errors'=>$validator->errors()->all()]);}
            $test = $this->testModel::query()->where(['id' => $request->uid])->first();
            $test->update(array('name_en' => $request->name_en));
            return response()->json(['success'=> true , 'data' => [$test]]);
        } catch (\Exception $e)
        {
            return response()->json(['success'=> false , 'errors' => [$e->getMessage()]]);
        }
    }

    public function get(Request $request){
        try{
            $test = Test::query()->find($request->uid);
            return response()->json(['data' => $test]);
        } catch (\Exception $e)
        {
            return response()->json(['success'=> false , 'errors' => [$e->getMessage()]]);
        }
    }

    public function delete(Request $request){
        $status = $this->testModel::query()->where('id', $request->uid)->update(array(BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::DELETE));
        return response()->json(['status'=> $status , 'msg' => 'Delete successful']);
    }

    public function restore(Request $request){
        $status = $this->testModel::query()->where('id', $request->uid)->update(array(BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE));
        return response()->json(['status'=> $status , 'msg' => 'Activate successful']);
    }

    /** TEST SAMPLES
     * @param Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     */

    public function testSamples(Request $request){
        if(!GlobalController::user_can(Auth::user()->role_id, ['view_test_sample'])) return redirect(url('my-profile'));
        $physicians = $this->physicianModel::query()->where(['lab_id' => $this->baseLabId, BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE])->get();
        $department = $this->departmentModel::query()->where(['lab_id' => $this->baseLabId, BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE])->orderBy('weight','asc')->get();
        $patientTypes = $this->patientTypeModel::query()->where(BaseModel::RECORD_STATUS_FIELD, RecordStatusEnum::ACTIVE)->get();
        $testItems = $this->testModel::query()->where(BaseModel::RECORD_STATUS_FIELD, RecordStatusEnum::ACTIVE)->get();
        $testSampleTable = $this->model::getTableNameByScheme();
        $sampleTypeTable = $this->sampleTypeModel::getTableNameByScheme();
        $departmentTable = $this->departmentModel::getTableNameByScheme();
        $testTable = $this->testModel::getTableNameByScheme();
        $testSamples = $this->model::query()->select([
            $departmentTable.'.name_en as department_name',
                $sampleTypeTable.'.name_en as sample_type_name',
                $testTable.'.name_en as test_name',
                $testSampleTable.'.*'
            ])
            ->join($sampleTypeTable, $testSampleTable.'.sample_type_id', '=', $sampleTypeTable.'.id')
            ->join($departmentTable, $sampleTypeTable.'.department_id', '=', $departmentTable.'.id')
            ->join($testTable, $testSampleTable.'.test_id', '=', $testTable.'.id')
            ->where($testSampleTable.'.'.BaseModel::RECORD_STATUS_FIELD, RecordStatusEnum::ACTIVE)
            ->where($testSampleTable.'.lab_id', $this->baseLabId)
            ->where($sampleTypeTable.'.'.BaseModel::RECORD_STATUS_FIELD, RecordStatusEnum::ACTIVE)
            ->when(!empty($request->sample_type), function ($query) use($sampleTypeTable, $request){
                $query->where($sampleTypeTable.'.id', $request->sample_type);
            })->when(!empty($request->department), function ($query) use($departmentTable, $request) {
                $query->where($departmentTable.'.id', $request->department);
            })->when(!empty($request->kword), function ($query) use($testTable, $testSampleTable, $request){
                $query->whereRaw( $testTable.".name_en like '%".addslashes($request->kword)."%'")
                    ->orWhereRaw($testSampleTable.".code like '%".addslashes($request->kword)."%'");
            })->when(Auth::id()==1, function ($query) use ($testSampleTable){
                $query->whereIn($testSampleTable.'.'.BaseModel::RECORD_STATUS_FIELD , [RecordStatusEnum::DELETE, RecordStatusEnum::ACTIVE]);
            })->orderBy($departmentTable.'.weight')
            ->orderBy($sampleTypeTable.'.weight')
            ->orderBy($testSampleTable.'.weight')
            ->paginate(20);
        return view('test', ['testSamples' => $testSamples, 'departments' => $department,
             'testItems' => $testItems, 'patientTypes' => $patientTypes, 'labSetting' => (object) $this->base,
            'physicians' => $physicians
        ]);
    }

    public function saveTestSample(TestSampleCreateRequest $request){
        set_time_limit(6000);
        ini_set('memory_limit', '10240M');
        DB::beginTransaction();
        try{
            if(!GlobalController::user_can(Auth::user()->role_id, ['create_test_sample'])) return false;
            $testSample = $this->model::query()->create([
                'sample_type_id' => $request->sample_type_id,
                'test_id' => $request->test_id,
                'group_result' => $request->group_result,
                'category' => NULL,
                'unit_sign' => $request->unit_sign,
                'code' => $request->code,
                'heading_id' => $request->heading_id,
                'usd_price' => $request->usd_price,
                'weight' => $request->weight,
                'field_type' => $request->filed_type_id,
                'formula' => $request->formula,
                'format' => $request->format_value,
                'description' => $request->description,
                'lab_id' => $this->baseLabId,
                'is_bold' => $request->is_bold,
                'autocomplete_bind' => $request->autocomplete_bind
            ]);
            // reference range
            if(in_array($request->filed_type_id,[1,4,6])){
                $data = collect($request->patient_type_ids);
                $items = $data->map(function ($row, $key) use ($request, $testSample) {
                    if(!empty($request->patient_type_ids[$key]['value'])) {
                        $testNormalValue = $this->testNormalValueModel::query()->create([
                            'test_sample_id' => $testSample->id,
                            'patient_type_id' => $request->patient_type_ids[$key]['value'],
                            'sign' => $request->signs[$key]['value'],
                            'minimum' => is_numeric($request->min_values[$key]['value']) ? $request->min_values[$key]['value'] : null,
                            'maximum' => is_numeric($request->max_values[$key]['value']) ? $request->max_values[$key]['value'] : null,
                        ]);
                    }
                    return [];
                });
            }
            // organism and antibiotics
            if(in_array($request->filed_type_id,[2,3]) ){
                $organismsCollection = collect($request->organisms);
                foreach ($organismsCollection as $org){
                    $this->testSampleOrganismModel::query()->create([
                        'test_sample_id' => $testSample->id,
                        'is_default' => $org['is_default'],
                        'organism_id' => $org['id'],
                        'lab_id' => $this->baseLabId
                    ]);
                }
            }
            DB::commit();
            return response()->json(['success' => true, 'message' => __('test_sample.create_success'), 'data' => [$testSample]]);
        } catch (\Exception $e){
            DB::rollBack();
            return response()->json(['success'=> false, 'message' => __('test_sample.create_fail'), 'errors' => [$e->getMessage()]]);
        }
    }

    public function getTestSample(Request $request){
        $testSample = $this->model::with([
            'sample',
            'organisms.organism',
            'testValues'
        ])->find($request->uid);
        return response()->json(['success'=> true , 'message' => __('test_sample.get_success'), 'data' => new TestSampleResource($testSample)]);
    }

    public function updateTestSample(TestSampleUpdateRequest $request){

        set_time_limit(6000);
        ini_set('memory_limit', '10240M');
        DB::beginTransaction();
        try{
            if(!GlobalController::user_can(Auth::user()->role_id, ['update_test_sample'])) return false;
            $testSample = $this->model::query()->where('id',$request->uid)->first();
            $testSample->update([
                'sample_type_id' => $request->sample_type_id,
                'test_id' => $request->test_id,
                'group_result' => $request->group_result,
                'category' => @$request->category,
                'unit_sign' => $request->unit_sign,
                'code' => $request->code,
                'heading_id' => $request->heading_id,
                'usd_price' => $request->usd_price,
                'weight' => $request->weight,
                'field_type' => $request->filed_type_id,
                'formula' => $request->formula,
                'format' => $request->format_value,
                'description' => $request->description,
                'is_bold' => $request->is_bold,
                'autocomplete_bind' => $request->autocomplete_bind
            ]);

            $this->testNormalValueModel::query()->where('test_sample_id', $testSample->id)->update([BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::DELETE]);
            $this->testSampleOrganismModel::query()->where('test_sample_id', $testSample->id)->update([BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::DELETE]);

            // reference range
            if(in_array($request->filed_type_id,[1,4,6])){
                $data = collect($request->patient_type_ids);
                $items = $data->map(function ($row, $key) use ($request, $testSample) {
                    if(!empty($request->patient_type_ids[$key]['value'])) {
                        $testNormalValue = $this->testNormalValueModel::query()->create([
                            'test_sample_id' => $testSample->id,
                            'patient_type_id' => $request->patient_type_ids[$key]['value'],
                            'sign' => $request->signs[$key]['value'],
                            'minimum' => is_numeric($request->min_values[$key]['value']) ? $request->min_values[$key]['value'] : null,
                            'maximum' => is_numeric($request->max_values[$key]['value']) ? $request->max_values[$key]['value'] : null,
                        ]);
                    }
                    return [];
                });
            }
            // organism and antibiotics
            if(in_array($request->filed_type_id,[2,3]) ){
                $organismsCollection = collect($request->organisms);
                $organisms = $organismsCollection->pluck('id')->unique()->toArray();
                $this->testSampleOrganismModel::query()->where(['test_sample_id' => $testSample->id])
                    ->whereNotIn('organism_id', $organisms)
                    ->update([BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::DELETE]);

                foreach ($organismsCollection as $org){
                    $testSampleOrganism = $this->testSampleOrganismModel::query()->create([
                        'test_sample_id' => $testSample->id,
                        'is_default' => $org['is_default'],
                        'organism_id' => $org['id'],
                        'lab_id' => $this->baseLabId
                    ]);
                }

            }
            DB::commit();
            return response()->json(['success' => true, 'message' => __('test_sample.update_success'), 'data' => [$testSample]]);
        } catch (\Exception $e){
            DB::rollBack();
            return response()->json(['success' => false, 'message' => __('test_sample.update_fail'), 'errors' => $e->getMessage()]);
        }
    }

    public function editTestSampleOrder(Request $request){
        DB::beginTransaction();
        try{
            if(!GlobalController::user_can(Auth::user()->role_id, ['update_test_sample'])) return false;
            $validator = \Validator::make($request->all(), ['id' => 'required', 'order_number' => 'required']);
            if ($validator->fails()){ return response()->json(['errors'=>$validator->errors()->all()]);}

            $testSample = $this->model::query()->where([
                'id' => $request->id,
                'lab_id' => $this->baseLabId
            ])->first();
            $testSample->update(['weight' => $request->order_number]);
            $batchUpdates = $this->model::query()->where([
                'sample_type_id' => $testSample->sample_type_id,
                'lab_id' => $this->baseLabId,
            ])->where('weight','>=', $request->order_number)->where('id','<>', $request->id)->update([
                'weight' => DB::raw('weight + 1')
            ]);
            DB::commit();
            return redirect()->back();
        } catch (\Exception $e){
            DB::rollBack();
            return redirect()->back();
        }
    }

    public function deleteTestSample(Request $request){
        DB::beginTransaction();
        try{
            if(!GlobalController::user_can(Auth::user()->role_id, ['delete_test_sample'])) return false;
            $this->model::query()->where('id', $request->uid)->update(array(BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::DELETE));
            $this->testNormalValueModel::query()->where('test_sample_id', $request->uid)->update([BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::DELETE]);
            $this->testSampleOrganismModel::query()->where('test_sample_id', $request->uid)->update([BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::DELETE]);
            DB::commit();
            return response()->json(['success' => true, 'message' => __('test_sample.delete_success')]);
        }
        catch (\Exception $e){
            DB::rollBack();
            return response()->json(['success' => false, 'message' => __('test_sample.delete_fail')]);
        }

    }

    public function restoreTestSample(Request $request){
        DB::beginTransaction();
        try{
            $this->model::query()->where('id', $request->uid)->update(array(BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE));
            $this->testNormalValueModel::query()->where('test_sample_id', $request->uid)->update([BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE]);
            $this->testSampleOrganismModel::query()->where('test_sample_id', $request->uid)->update([BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE]);
            DB::commit();
            return response()->json(['success' => true, 'message' => __('test_sample.restore_success')]);
        }
        catch (\Exception $e){
            DB::rollBack();
            return response()->json(['success' => false, 'message' => __('test_sample.restore_fail')]);
        }
    }

    public function storePhysicianCommission(Request $request){
        DB::beginTransaction();
        try{
            foreach ($request->physician as $k=>$val){
                $this->physicianCommissionModel::query()->updateOrCreate([
                    'physician_id' => $request->physician[$k],
                    'test_sample_id' => $request->test_sample_id
                ],[
                    'physician_id' => $request->physician[$k],
                    'test_sample_id' => $request->test_sample_id,
                    'commission_rate' => $request->commission_rate[$k],
                    'partner_price' => $request->pc_price[$k],
                    'commission_type' => $request->commission_type[$k],
                    'lab_id' => $this->baseLabId,
                    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 redirect()->back();
        }
        catch (\Exception $e){
            DB::rollBack();
            return redirect()->back();
        }
    }

    public function setCommissionToAllTest(Request $request){
        DB::beginTransaction();
        try{
            $testSamples = $this->model::query()->where(['lab_id' => $this->baseLabId, BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE])->get();
            foreach ($testSamples as $testSample){
                $this->physicianCommissionModel::query()->updateOrCreate([
                    'physician_id' => $request->physician_id,
                    'test_sample_id' => $testSample->id
                ],[
                    'physician_id' => $request->physician_id,
                    'test_sample_id' => $testSample->id,
                    'commission_rate' => $request->commission_rate,
                    'commission_type' => $request->commission_type,
                    'lab_id' => $this->baseLabId,
                    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' => __('test_sample.add_commission_success')]);
        }
        catch (\Exception $e){
            DB::rollBack();
            return response()->json(['success'=> false , 'message' => __('test_sample.add_commission_fail'), 'errors' => $e->getMessage()]);
        }
    }


    /*public function cloneTestSampleProperties(Request $request){
        try {

            $test_sample_id = $request->test_sample_id;
            $target_lab_id = $request->target_lab_id;
            $target_sample_type_id = $request->target_sample_type_id;
            $target_test_sample_id = $request->target_test_sample_id;

            $testSamples = $this->model::with(['testValues','organisms','organisms.antibiotics'])->where('id', $test_sample_id)->get();

            $this->testNormalValueModel::query()->where(['test_sample_id' => $target_test_sample_id])->update([BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::DELETE]);
            $this->testSampleOrganismModel::query()->where(['test_sample_id' => $target_test_sample_id, 'lab_id' => $target_lab_id])->update([BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::DELETE]);

            foreach ($testSamples as $testSample) {
                $testValues = isset($testSample->testValues) ? $testSample->testValues : [];

                foreach ($testValues as $testValue) {
                    $testValueData = [
                        'test_sample_id' => $target_test_sample_id,
                        'patient_type_id' => $testValue->patient_type_id,
                        'sign' => $testValue->sign,
                        'minimum' => $testValue->minimum,
                        'maximum' => $testValue->maximum,
                        'created_at' => date('Y-m-d H:i:s'),
                        'created_by' => 1
                    ];
                    $insertTestValue = $this->testNormalValueModel::query()->create($testValueData);
                }
                $testOrganisms = isset($testSample->organisms) ? $testSample->organisms : [];
                foreach ($testOrganisms as $testOrganism) {
                    $testOrganismData = [
                        'test_sample_id' => $target_test_sample_id,
                        'organism_id' => $testOrganism->organism_id,
                        'lab_id' => $target_lab_id,
                        'created_at' => date('Y-m-d H:i:s'),
                        'created_by' => 1
                    ];
                    $insertTestSampleOrganism = $this->testSampleOrganismModel::query()->create($testOrganismData);
                    $antibiotics = isset($testOrganism->antibiotics) ? $testOrganism->antibiotics : [];
                    foreach ($antibiotics as $antibiotic) {
                        $testOrganismAntibioticData = [
                            'test_sample_organism_id' => $insertTestSampleOrganism->id,
                            'antibiotic_id' => $antibiotic->antibiotic_id,
                            'created_at' => date('Y-m-d H:i:s'),
                            'created_by' => 1
                        ];
                        $insertTestOrganismAntibiotic = $this->testSampleOrganismAntibioticModel::query()->create($testOrganismAntibioticData);
                    }
                }
            }
        }
        catch (\Exception $e){
            Log::error($e->getMessage());
        }
        return redirect()->back();
    }*/


}
