<?php

namespace App\Http\Controllers\IpdAdmission;

use App\Http\Controllers\Controller;
use App\Imports\BedsImport;
use App\Imports\MarketImport;
use App\Models\Account;
use App\Models\Bed;
use App\Models\BedGroup;
use App\Models\BedType;
use App\Models\Building;
use App\Models\Company;
use App\Models\Floor;
use App\Models\Room;
use App\Models\IpdBedHistory;
use App\Models\SaleInvoice;
use App\Models\SaleInvoiceDetail;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;
use DB;
use Carbon\Carbon;
use App\Exports\BedStatementExport;


class BedController extends Controller
{
    function __construct()
    {
        $this->middleware('permission:beds-list', ['only' => ['index']]);
    }
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        $data = Bed::with('getBedType', 'getBedGroup','getFloor','getBuilding','getRoom','getIpdAdmission');
        // dd($data);
        if ($request->ajax()) {
            $sort_by      = $request->get('sortby') ?? 10;
            $sort_type    = $request->get('sorttype');
            $search_query = $request->get('query');
            $bed_filter   = $request->get('bedFilter');

            $bed_availability = $bed_filter == 'available_beds' ? 1 : ($bed_filter == 'booked_beds' ? 0 : '');

            $data = $data->when(!empty($search_query), function ($query) use ($search_query) {
                return $query->where(function ($query) use ($search_query) {
                    $query->whereHas('getBedGroup', function ($bedGroupQuery) use ($search_query) {
                        $bedGroupQuery->where('name', 'like', '%' . $search_query . '%');
                    })
                    ->orWhereHas('getBedType', function ($bedTypeQuery) use ($search_query) {
                        $bedTypeQuery->where('name', 'like', '%' . $search_query . '%');
                    })
                    ->orWhere('beds.name', 'like', '%' . $search_query . '%')
                    ->orWhere('beds.note', 'like', '%' . $search_query . '%');
                });
            })
            ->when(!empty($bed_availability), function ($query) use ($bed_availability) {
                $query->where('bed_available', $bed_availability);
            })
            ->paginate($sort_by);
            return view('beds.table', compact('data'));
        }
        else
        {
            $data = $data->paginate(10);

            return view('beds.index', compact('data'));
        }
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */

    public function statement(Request $request)
    {

        if ($request->ajax()) {

            $from_date = $request->from_date ?
                Carbon::createFromFormat($this->companyDateFormate(), $request->from_date)->format('Y-m-d')
                    :date('Y-m-d');
            $to_date   = $request->to_date ?
                Carbon::createFromFormat($this->companyDateFormate(), $request->to_date)->format('Y-m-d')
                    :date('Y-m-d');

            $filters                      = $where        = [];
            $filters['from_date']         = date('Y-m-d', strtotime($from_date));
            $filters['to_date']           = date('Y-m-d', strtotime($to_date));
            $filters['search_bed']        = $request->search_bed != '' ? $request->search_bed : '';
            $filters['search_bed_status'] = $request->search_bed_status != '' ? $request->search_bed_status : '';
            $filters['search_bed_group']  = $request->search_bed_group != '' ? $request->search_bed_group : '';
            $filters['search_bed_type']   = $request->search_bed_type != '' ? $request->search_bed_type : '';
            $fromDate                     = date('Y-m-d H:i:s',strtotime($from_date));
            $toDate                       = date('Y-m-d H:i:s',strtotime($to_date));
            $bedsinfo                     = Bed::getStatement($where, $filters);
            
           

            return view('beds.statement.statement-table', compact([
                'fromDate',
                'toDate',
                'bedsinfo' ,
            ]));
        }

        $from_date = $request->from_date ?
                Carbon::createFromFormat($this->companyDateFormate(), $request->from_date)->format('Y-m-d')
                    :date('Y-m-d');
        $to_date   = $request->to_date ?
                Carbon::createFromFormat($this->companyDateFormate(), $request->to_date)->format('Y-m-d')
                    :date('Y-m-d');

        $bedsinfo   = Bed::getStatement();
        $bed_groups = BedGroup::select('id', 'name')->where('is_active',1)->get();
        $bed_types  = BedType::select('id', 'name')->get();

          return view('beds.statement.statement', compact([
            'from_date', 
            'to_date' ,
            'bedsinfo' ,
            'bed_groups' ,
            'bed_types' ,
        ]));
    }


    public function exportStatement(Request $request)
    {

        $from_date = $request->from_date ?
            Carbon::createFromFormat($this->companyDateFormate(), $request->from_date)->format('Y-m-d')
                :date('Y-m-d');
        $to_date   = $request->to_date ?
            Carbon::createFromFormat($this->companyDateFormate(), $request->to_date)->format('Y-m-d')
                :date('Y-m-d');

            $filters                      = $where        = [];
            $filters['from_date']         = date('Y-m-d', strtotime($from_date));
            $filters['to_date']           = date('Y-m-d', strtotime($to_date));
            $filters['search_bed']        = $request->search_bed != '' ? $request->search_account : '';
            $filters['search_bed_status'] = $request->search_bed_status != '' ? $request->search_bed_status : '';
            $filters['search_bed_group']  = $request->search_bed_group != '' ? $request->search_bed_group : '';
            $filters['search_bed_type']   = $request->search_bed_type != '' ? $request->search_bed_type : '';          
  

        $data     = Bed::getStatement($where, $filters)->toArray();
        $fileName = 'beds-history-Statement'.' From '. $from_date.' To '.$to_date.'.xlsx';

        return Excel::download(new BedStatementExport($data), $fileName);
    }


    public function create()
    {
        $bed_group = BedGroup::select('id', 'name')->where('is_active',1)->get();
        $bed_type  = BedType::select('id', 'name')->get();
        $priority  = Bed::max('priority');
        $priority  = $priority != '' ? $priority : 0;
        $buildings = Building::select(['id','name','default'])->get();
        $floors    = Floor::select(['id','name'])->get();

        return view('beds.create', compact('bed_group','bed_type','priority','buildings','floors'));
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $validator = \Validator::make($request->all(), [
            'name'         => 'required|unique:beds',
            'bed_type_id'  => 'required',
            'bed_group_id' => 'required',
            'building_id'  => 'required',
            'floor_id'     => 'required',

        ],
        [
            'bed_group_id.required' => 'Bed Group is Required/Please Select Group',
            'bed_type_id.required'  => 'Bed Type is Required/Please Select Bed Type',
            'building_id.required'  => 'Building is Required/Please Select Building Type',
            'floor_id.required'     => 'Floor is Required/Please Select Floor Type',
        ]);

        if ($validator->fails()) {
            if ($request->ajax()) {
                return response()->json([
                    'success' => false,
                    'message' => $validator->getMessageBag()->first(),
                    'data'    => []
                ]);
            }
            return redirect()->back()->with('error', $validator->getMessageBag()->first());
        }

        $data = $request->except([
            '_token',
            '_method'
        ]);

        $data['company_id'] = \Auth::user()->company_id;

        $source = Bed::create($data);

        if ($request->ajax()) {
            return response()->json([
                'success' => true,
                'message' => 'Bed Group Created successfully',
                'data'    => $source
            ]);
        }
        return redirect()->route('beds.index')
            ->with('success', 'Bed Group created successfully');
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        $room      = Room::select('id', 'room_number','room_name','building_id','floor_id')->where('status',1)->get();
        $bed       = Bed::find($id);
        $bed_group = BedGroup::select('id', 'name')->get();
        $bed_type  = BedType::select('id', 'name')->get();
        $buildings = Building::select(['id','name','default'])->get();
        $floors    = Floor::select(['id','name'])->get();
        $patient   = '';
        if (!empty($data) && isset($data['patient_id']) && $data['patient_id'] != '') {
            $patient = Account::getAccount([
                        'account_types.type_code' => 'PATIENT',
                        'accounts.id'             => $data['patient_id']
                    ]);
            if (isset($patient)) {
                $patient->full_name = $patient->name .
                    ($patient->code     != '' ? ', ' . $patient->code : '') .
                    ($patient->gender   != '' ? ', ' . $patient->gender : '') .
                    ($patient->age      != '' ? ', ' . $patient->age . ' yrs' : '') .
                    ($patient->phone_no != '' ? ', ' . $patient->phone_no : '');
            }
        }

        return view('beds.edit', compact('bed_group','bed_type','bed','patient','room','buildings','floors'));
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $validator = \Validator::make($request->all(), [
            'name'         => 'required|unique:beds,name,' . $id,
            'bed_type_id'  => 'required',
            'bed_group_id' => 'required',
            'building_id'  => 'required',
            'floor_id'     => 'required',
        ],[
        'bed_group_id.required' => 'Bed Group is Required/Please Select Group',
        'bed_type_id.required'  => 'Bed Type is Required/Please Select Bed Type',
        'building_id.required'  => 'Building is Required/Please Select Building Type',
        'floor_id.required'     => 'Floor is Required/Please Select Floor Type',
        ]);

        if ($validator->fails()) {
            if ($request->ajax()) {
                return response()->json([
                    'success' => false,
                    'message' => $validator->getMessageBag()->first(),
                    'data'    => []
                ]);
            }
            return redirect()->back()->with('error', $validator->getMessageBag()->first());
        }

        $data = $request->except([
            '_token',
            '_method'
        ]);

        $source = Bed::find($id);

        if (!$source) {
            return redirect()->route('beds.index')
                ->with('error', 'Bed not found!');
        }
        $data['company_id'] = \Auth::user()->company_id;

        $source->update($data);

        if ($request->ajax()) {
            return response()->json([
                'success' => true,
                'message' => 'Bed updated successfully',
                'data'    => $source
            ]);
        }
        return redirect()->route('beds.index')
            ->with('success', 'Bed updated successfully');
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy(Request $request)
    {
        Bed::find($request->id)->delete();

        $Redirect = 'beds';

        return response()->json([
            'success' => true,
            'message' => ['Deleted successfully'],
            'data' => [
                    'redirect' => $Redirect,
                ]
        ]);
    }

    public function changeStatus(Request $request)
    {
        if ($request->ajax()) {
            $data   = array('status' => $request->status );
            $Update = Bed::where('id', '=', $request->id)->update($data);

            if($Update){
                return response()->json([
                    'success'=>true,
                    'message'=>['Bed status successfully change'],
                    'data'=>[
                       'redirect'=>'/users/',
                       'reload'=>true,
                    ]
                ]);
            } else {
                return response()->json([
                   'success'=>false,
                   'message'=>['Error for change status'],
                   'data'=>[
                       'redirect'=>'',
                   ]
                ]);
            }
        }
    }
    public function waitingPatient(Request $request)
    {
        if ($request->ajax()) {
            $data   = array('waiting_ipd_admission_id' => $request->status );
            $Update = Bed::where('id', '=', $request->id)->update($data);

            if($Update){
                return response()->json([
                    'success'=>true,
                    'message'=>['Waiting Patient status successfully change'],
                    'data'=>[
                       'redirect'=>'/users/',
                       'reload'=>true,
                    ]
                ]);
            } else {
                return response()->json([
                   'success'=>false,
                   'message'=>['Error for change status'],
                   'data'=>[
                       'redirect'=>'',
                   ]
                ]);
            }
        }
    }

    public function filterBeds(Request $request)
    {
       if ($request->ajax()) {
            $bed_availability = $request->filter == 'available_beds' ? 1 : ($request->filter == 'booked_beds' ? 0 : '');

            $data = Bed::with('getBedType', 'getBedGroup')->where('bed_available', $bed_availability)->paginate(10);

            return view('beds.table', compact('data'));
        }
    }

    public function viewImport()
    {
        $company  = Company::select('id','name')
        ->where('status','1')->get();
        return view('beds.import',compact('company'));
    }
    
    public function bedImport(Request $request)
    {
        $data = \Session::get('beds_import') ?? [];

        $data['successImport'] = 0;
        $data['errorImport'] = 0;

        \Session::put('beds_import', $data);

        if($request->file('beds_import')){
            $file = $request->file('beds_import');
            
            $validator =  \Validator::make($request->all(), [
              'beds_import' => 'required|mimes:csv,xlsx,xls|max:5000',
            ]);

            if ($validator->fails()) {
                return redirect()->back()->with('error', $validator->errors()->all());
            }
        }

        $collection = Excel::import(new BedsImport($request),
        $request->file('beds_import'));
        $data       = \Session::get('beds_import') ?? [];
        $message    = 'File uploaded successfully. ' . $data['successImport'] . ' New Records added, ' . $data['errorImport'] . ' Records already exist.';

        return redirect()->route('beds.index')->with('success', $message);
    }

    public function bedsavailable(Request $request)
    {

        if ($request->ajax()) {
            $company_id  = $request->get('company_id');
            $building_id = $request->get('building_id');

            $bed_groups = BedGroup::get()
                ->groupBy('id')
                ->map(function ($bed_groups, $id) use ($building_id, $company_id) {
                    $floor = Floor::select(
                                'floors.id',
                                'floors.name' ,
                                DB::raw('COUNT(beds.id) as total_beds')
                            )
                            ->leftJoin('bed_groups' , function($join) use ($id){
                                $join->on('bed_groups.floor_id' , '=' , 'floors.id')
                                    ->where('bed_groups.id' , $id);
                            })
                            ->leftjoin('beds', function($join) use ($company_id) {
                                $join->on('beds.floor_id' , '=' , 'floors.id')
                                    ->when(!empty($company_id), function($query) use ($company_id) {
                                        $query->where('beds.company_id', $company_id)
                                        ->where('beds.bed_group_id' , $id)
                                        ->where('beds.bed_available' , '1');

                                    });
                            })
                            ->when(!empty($building_id), function($query) use ($building_id) {
                                $query->where('floors.building_id', $building_id);
                            })
                            ->groupBy('floors.id')
                            ->orderBy('floors.id')
                            ->get();

                    return [
                        'floor' => $floor,
                        'data'  => $bed_groups,
                    ];
                });
            $floors = Floor::select(
                    'floors.id',
                    'floors.name' ,
                )
                ->when(!empty($building_id), function($query) use ($building_id) {
                    $query->where('building_id', $building_id);
                })
                ->orderBy('floors.id')
                ->get();

            return view('ipd-admission-bed-available.table' ,compact('floors' , 'bed_groups'));
        } else {
            $companies  = Company::get();
            $buildings  = Building::get();
            $bed_groups = BedGroup::get()
                ->where('is_active' , '1')
                ->groupBy('id')
                ->map(function ($bed_groups, $id) {
                    $floor = Floor::select(
                                'floors.id',
                                'floors.name' ,
                                DB::raw('COUNT(beds.id) as total_beds')
                            )
                            ->leftJoin('bed_groups' , function($join) use ($id){
                                $join->on('bed_groups.floor_id' , '=' , 'floors.id')
                                    ->where('bed_groups.id' , $id);
                            })
                            ->leftJoin('beds' , function($join) use ($id){
                                $join->on('beds.floor_id' , '=' , 'floors.id')
                                  ->where('beds.bed_group_id' , $id)
                                  ->where('beds.bed_available' , '1');
                            })
                            ->groupBy('floors.id')
                            ->orderBy('floors.id')
                            ->get();
                    
                    return [
                        'floor' => $floor,
                        'data'  => $bed_groups ,
                    ];
                });
            $floors = Floor::select(
                    'floors.id',
                    'floors.name' ,
                )
                ->orderBy('floors.id')
                ->get();

            return view('ipd-admission-bed-available.index' ,compact('floors' , 'bed_groups' , 'companies' , 'buildings'));
        }
    }

    public function bedstatus(Request $request)
    {
        $data = Floor::leftJoin('rooms', 'rooms.floor_id', '=', 'floors.id')
            ->leftJoin('beds', 'beds.room_id', '=', 'rooms.id')
            ->leftJoin('ipd_bed_histories', 'ipd_bed_histories.bed_no_id', '=', 'beds.id')
            ->leftJoin('ipd_admissions', 'ipd_bed_histories.ipd_admission_id', '=', 'ipd_admissions.id')
            ->leftJoin('accounts', 'ipd_admissions.patient_id', '=', 'accounts.id')
            ->leftJoin('account_contacts', 'accounts.id', '=', 'account_contacts.id')
            ->leftJoin('genders', 'account_contacts.account_gender_id', '=', 'genders.id')
            ->leftJoin('bed_types', 'bed_types.id', '=', 'beds.bed_type_id')
            ->leftJoin('bed_groups', 'bed_groups.id', '=', 'beds.bed_group_id')
            ->select(
                'bed_groups.id as bed_group',
                'floors.id as floor',
                'floors.name as floor_name',
                'bed_groups.name as bed_group_name',
                'beds.name as bed_name',
                'beds.bed_available as bed_available',
                'accounts.name as patient_name',
                'ipd_admissions.id as admission_id',
                'account_contacts.phone_no as phone_number',
                DB::raw('TIMESTAMPDIFF(YEAR, account_contacts.date_of_birth, CURDATE()) as age'),
                'genders.name as gender_name'
            )
            ->orderBy('floors.priority')
            ->orderBy('bed_groups.name')    
            ->orderBy('beds.name');

        if ($request->ajax()) {
            $search_query = $request->get('query');
            $search_type = $request->get('search_type');    

            $data = $data->when(!empty($search_query) && !empty($search_type), function ($query) use ($search_type, $search_query) {
                if ($search_type == 'floor_name') {
                    $query->where('floors.name', 'LIKE', '%' . $search_query . '%');
                } elseif ($search_type == 'bed_group_name') {
                    $query->where('bed_groups.name', 'LIKE', '%' . $search_query . '%');
                } elseif ($search_type == 'bed_name') {
                    $query->where('beds.name', 'LIKE', '%' . $search_query . '%');
                } elseif ($search_type == 'patient_name') {
                    $query->where('accounts.name', 'LIKE', '%' . $search_query . '%');
                }
            });

            $data = $data->get()
                ->groupBy('floor')
                ->map(function ($data, $floorId) {
                    $floor     = Floor::find($floorId);
                    $bedGroups = $data->groupBy('bed_group')
                        ->map(function ($beds, $bedGroupId) {
                            $bedGroup = BedGroup::find($bedGroupId);
                            return [
                                'bed_group' => $bedGroup->name ?? '',
                                'data'      => $beds,
                            ];
                        });
                    return [
                        'floor' => $floor->name ?? '',              
                        'data'  => $bedGroups,
                    ];
                });                

            return view('ipd-admission-bed-status.table', compact('data')); 
        } else {
            $data = $data->get()
                ->groupBy('floor')
                ->map(function ($data, $floorId) {
                    $floor     = Floor::find($floorId);
                    $bedGroups = $data->groupBy('bed_group')
                        ->map(function ($beds, $bedGroupId) {
                            $bedGroup = BedGroup::find($bedGroupId);
                            return [
                                'bed_group' => $bedGroup->name ?? '',
                                'data'      => $beds,
                            ];
                        });
                    return [
                        'floor' => $floor->name ?? '',
                        'data'  => $bedGroups,
                    ];
                });

            return view('ipd-admission-bed-status.index', compact('data'));
        }
    }

    public function refreshBilling($id) {
        $bed = IpdBedHistory::select('ipd_bed_histories.*','bed_types.product_id')
            ->leftJoin('beds', 'ipd_bed_histories.bed_no_id', '=', 'beds.id')
            ->leftJoin('bed_types', 'beds.bed_type_id', '=', 'bed_types.id')
            ->leftJoin('products', 'bed_types.product_id', '=', 'products.id')
            ->find($id);


        if (!$bed) {
            return response()->json([
               'success' => false,
               'message' => 'Bed History not found!',
            ]);
        }

        $sale_details = SaleInvoiceDetail::where([
                'product_id' => $bed->product_id,
                'batch_id'   => $bed->sale_invoice_batch_id
            ])
            ->first();

        if (!$sale_details) {
            return response()->json([
               'success' => false,
               'message' => 'Sale invoice details not found!',
            ]);
        }

        $total_amount     = $sale_details->total_amount ?? 0;
        $main_qty         = $sale_details->main_qty ?? 0;
        $price            = $main_qty != 0 ? $total_amount/$main_qty : 0;
        $checkin          = Carbon::parse($bed->check_in_date_time);
        $checkout         = !empty($bed->check_out_date_time) ? Carbon::parse($bed->check_out_date_time) : Carbon::now();
        $quantity         = $checkin->diffInDays($checkout);
        $quantity         = (int)$quantity + 1;
        $new_total_amount = $quantity * $price;

        $sale_details->update(['total_amount' => $new_total_amount, 'main_qty' => $quantity]);

        $sale_invoice = SaleInvoice::where(['id' => $sale_details->sale_invoice_id])->first();
        $sale_invoice->update([
            'billing_amount' => (($sale_invoice->billing_amount - $total_amount) + $new_total_amount)
        ]);
        $bed->update(['is_updated'=>0]);

        return response()->json([
           'success' => true,
           'message' => 'Billing updated successfully.',
        ]);
    }

    public function getRoom(Request $request)
    {
        $rooms = Room::where(['building_id'=>$request->building_id,'floor_id'=>$request->floor_id,'status'=>1])->get(['id','room_number','room_name as name']);
        return response()->json($rooms);
    }
}
