<?php

namespace App\Http\Controllers;
use App\Enums\RecordStatusEnum;
use App\Http\Controllers\Helper\GlobalController;
use App\Http\Requests\SampleCreateRequest;
use App\Http\Requests\UpdateRequests\SampleUpdateRequest;
use App\Http\Resources\SampleResource;
use App\Models\BaseModel;
use App\Models\Invoice;
use App\Models\InvoiceDetail;
use App\Models\Patient;
use App\Models\Sample;
use App\Models\LabConfigure;
use App\Models\Physician;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;

class InvoiceController extends Controller
{
    protected $model;
    protected $sampleModel;
    protected $patientModel;
    protected $invoiceDetailModel;
    protected $baseLabId;
    protected $labs;
    protected $base;
    protected $laboratoryConfigures;
    protected $physicianModel;


    public function __construct(Invoice $invoiceModel, InvoiceDetail $invoiceDetailModel, Sample $sampleModel, Patient $patientModel, Physician $physicianModel){
        $this->model = $invoiceModel;
        $this->sampleModel = $sampleModel;
        $this->invoiceDetailModel = $invoiceDetailModel;
        $this->patientModel = $patientModel;
        $this->laboratoryConfigures = new LabConfigure();
        $this->physicianModel = $physicianModel;

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

    public function index(Request $request){
        if(!GlobalController::user_can(Auth::user()->role_id, ['view_invoice'])) return redirect(url('my-profile'));
        $recordStatusConditions = Auth::id()==1 ? [RecordStatusEnum::ACTIVE , RecordStatusEnum::DELETE] : [RecordStatusEnum::ACTIVE];

         $oweInvoices = $this->model::with(['sample.patient'])->where(['lab_id' => $this->baseLabId, BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE])
            ->where('balance','>', 0)->get();
        $physicians = $this->physicianModel::query()->where(['lab_id' => $this->baseLabId, BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE])->get();

        $invoices = $this->model::with(['sample','repayments'])
            ->whereIn(BaseModel::RECORD_STATUS_FIELD, $recordStatusConditions)
            ->where('lab_id', $this->baseLabId)
            ->when(!empty($request->from_date) && !empty($request->to_date), function ($inv) use ($request){
                $inv->whereBetween('invoice_date',[date('Y-m-d',strtotime($request->from_date)), date('Y-m-d',strtotime($request->to_date))]);
            })
            ->when(isset($request->physician) && !empty($request->physician), function($inv) use ($request){
                $inv->whereIn('sample_id', $this->sampleModel::query()->where('physician_id', $request->physician)->pluck('id'));
            })
            ->when(!empty(trim($request->kword)), function ($inv) use($request, $recordStatusConditions){
                $inv->whereRaw("replace(invoice_code, ' ','') like '%".str_replace(" ","",$request->kword)."%'")
                    ->orWhereIn('sample_id', $this->sampleModel::query()
                        ->whereIn('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()
                        )->orwhereRaw("replace(sample_number, ' ','') like '%".str_replace(" ","",$request->kword)."%'")->pluck('id')->toArray()
                    )->where('lab_id', $this->baseLabId)->whereIn(BaseModel::RECORD_STATUS_FIELD, $recordStatusConditions);
            })->orderBy('invoice_code','desc')->paginate(20);
            if(Auth::id()==1){
                //dd($invoices->pluck('repayments'));
            }
        return view('v_invoice.invoice', ['invoices' => $invoices, 'labSettings' => (object) $this->location(), 'oweInvoices' => $oweInvoices, 'physicians' => $physicians]);
    }

    public function create($sample_id = null){
        if(!GlobalController::user_can(Auth::user()->role_id, ['create_invoice'])) return redirect(url('my-profile'));
        $samples = $this->sampleModel::query()->with('invoice')
            ->where(['lab_id' => $this->baseLabId, BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE])
            ->whereDoesntHave('invoice')->get();
        return view('v_invoice.new_invoice', [
            'samples' => $samples,
            'sample_id' => $sample_id
        ]);
    }

    public function store(Request $request){
        DB::beginTransaction();
        try{
            if(!GlobalController::user_can(Auth::user()->role_id, ['create_invoice'])) return redirect(url('my-profile'));
            $invoiceNumber = $this->generateAutoId($request->invoice_date);
            $is_hide_discount = isset($request->is_hide_discount) ? 1: 0;
            $requests = collect($request)->merge(['lab_id'=>$this->baseLabId, 'invoice_code' => $invoiceNumber, 'is_hide_discount' => $is_hide_discount, 'exchange_rate' => ((object) $this->location())->exchange_rate])->except(['first_paid_date']);
            $invoice = $this->model::query()->create($requests->all());
            $invoiceDetailRequest = collect($request->test_sample_id);
            $items = $invoiceDetailRequest->map(function ($row, $key) use($request, $invoice) {
                $invoiceDetailRow = $this->invoiceDetailModel::query()->create([
                    'invoice_id' => $invoice->id,
                    'test_sample_id' => $request->test_sample_id[$key],
                    'discount_type' => $request->item_discount_type[$key],
                    'discount' => $request->item_discount[$key],
                    'test_name' => $request->test_name[$key],
                    'qty' => 1,
                    'unit_price' =>  $request->unit_price[$key],
                ]);
                return [];
            });
            DB::commit();
            $request->session()->flash('message','invoice-success');
            if(isset($request->save_print_invoice) && $request->save_print_invoice=='save_preview_invoice'){
                return redirect('invoice/edit/'.$invoice->id.'?print');
            }
            return redirect()->back();
        } catch (\Exception $e){
            DB::rollBack();
            $request->session()->flash('message','invoice-error');
            return redirect()->back();
        }
    }

    public function edit($id){
        if(!GlobalController::user_can(Auth::user()->role_id, ['view_invoice', 'update_invoice'])) return redirect(url('my-profile'));
        $invoice = $this->model::query()->with('invoiceDetail.testSample.sample.department','creator','modifier')->where(['lab_id' => $this->baseLabId, 'id' => $id])->first();

        $samples = $this->sampleModel::query()->where('id', $invoice->sample_id)->first();

        $refreshItemItem = $this->refreshItemItem($invoice->sample_id);


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

        return view('v_invoice.edit_invoice', [
            'samples' => [$samples],
            'invoice' => $invoice,
            'invoice_id' => $id,
            'sample_id' => $invoice->sample_id,
            'labSettings' => (object) $this->location(),
            'refreshItemItem' => $refreshItemItem,
            'labConfigures' => $labConfigures,
            'is_need_refresh_invoice' => (count($refreshItemItem) == count($invoice->invoiceDetail)) ? 0 : 1
        ]);
    }

    public function update(Request $invoiceUpdateRequest){
        DB::beginTransaction();
        try{
            if(!GlobalController::user_can(Auth::user()->role_id, ['update_invoice'])) return redirect(url('my-profile'));
            $is_hide_discount = isset($invoiceUpdateRequest->is_hide_discount) ? 1: 0;
            $requests = collect($invoiceUpdateRequest)->only(['invoice_note','total','discount','gross_total','deposit' ,'bank_deposit', 'balance','invoice_date','exchange_rate'])->merge(['is_hide_discount' => $is_hide_discount, 'updated_by' => Auth::id(), 'updated_at' => date('Y-m-d H:i:s')]);
            $invoice = $this->model::query()->where(['id' => $invoiceUpdateRequest->uid, 'lab_id' => $this->baseLabId])->update($requests->all());
            $invoiceDetailRequest = collect($invoiceUpdateRequest->test_sample_id);
            $items = $invoiceDetailRequest->map(function ($row, $key) use($invoiceUpdateRequest) {
                $invDetail = $this->invoiceDetailModel::query()->where(['invoice_id' => $invoiceUpdateRequest->uid, 'test_sample_id' => $invoiceUpdateRequest->test_sample_id[$key]])->first();
                if (empty($invDetail)) {
                    $invoiceDetailRow = $this->invoiceDetailModel::query()->create([
                        'invoice_id' => $invoiceUpdateRequest->uid,
                        'test_sample_id' => $invoiceUpdateRequest->test_sample_id[$key],
                        'discount_type' => $invoiceUpdateRequest->item_discount_type[$key],
                        'discount' => $invoiceUpdateRequest->item_discount[$key],
                        'test_name' => $invoiceUpdateRequest->test_name[$key],
                        'weight' => $invoiceUpdateRequest->weight[$key],
                        'qty' => 1,
                        'unit_price' => $invoiceUpdateRequest->unit_price[$key],
                    ]);
                }
                else{
                    $invoiceDetailRow = $this->invoiceDetailModel::query()->where([
                            'invoice_id' => $invoiceUpdateRequest->uid,
                            'test_sample_id' => $invoiceUpdateRequest->test_sample_id[$key]
                        ])->update([
                        'weight' => $invoiceUpdateRequest->weight[$key]
                    ]);
                }
                return [];
            });
            $this->invoiceDetailModel::query()->where('invoice_id', $invoiceUpdateRequest->uid)
                ->whereNotIn('test_sample_id', $invoiceUpdateRequest->test_sample_id)->delete();
            DB::commit();
            $invoiceUpdateRequest->session()->flash('message','invoice-success');
            return redirect()->back();
        } catch (\Exception $e){
            DB::rollBack();
            $invoiceUpdateRequest->session()->flash('message','invoice-error');
            return redirect()->back();
        }
    }

    /** Perform by ajax function
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */

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

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

    public function getSampleTest($sampleId){
        try{
            $patientTypes = $this->sampleModel::query()->with([])->where([
                BaseModel::RECORD_STATUS_FIELD => RecordStatusEnum::ACTIVE,
                'lab_id' => $this->baseLabId
            ])->get();
            return response()->json(['success'=> true , 'data' => $patientTypes]);
        } catch (\Exception $e)
        {
            return response()->json(['success'=> false , 'errors' => $e->getMessage()]);
        }
    }

    public function generateAutoId($invoiceDate){
        $prefix = date('y',strtotime($invoiceDate));
        $invoiceCount = $this->model::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));
    }

    public function paid($id){
        DB::beginTransaction();
        try{
            $invoice = $this->model::query()->find($id);
            $invoice->balance = 0;
            $invoice->deposit = $invoice->gross_total;
            $invoice->first_paid_date = date('Y-m-d');
            $invoice->save();
            DB::commit();
            return response()->json(['success' => true, 'message' => __('This invoice already paid')]);
        } catch (\Exception $e){
            DB::rollBack();
            return response()->json(['success' => false, 'message' => __('Failed while trying to paid on invoice'), 'errors' => $e->getMessage()]);
        }
    }

    function refreshItemItem($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))),2);
                $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();
        }
    }

}
