<?php


namespace Mehrab\OrderService\Repositories;


use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Mehrab\OrderService\Models\CancelOrdersService;
use Mehrab\OrderService\Models\OrderService;
use Mehrab\Region\Repositories\RegionRepo;
use Mehrab\RolePermission\Models\Permission;
use function Composer\Autoload\includeFile;

class OrderServiceRepo
{

    public function update_price($order,$price){
        $order->update(["price"=>$price]);
    }
    public function add_coupon_to_meta($order,$coupon){
        $meta = $order->meta;
        $meta['coupon'] = $coupon->name;
        return $order->update([
            'meta' => $meta,
        ]);
    }

    public function store_order_frontend($request, $user_address, $operator_users, $service, $answers, $idMedia, $price)
    {
        $code = generateCode();
        $message = 'این سفارش با کد رهگیری ' . $code . ' توسط مشتری با شماره تماس ' . request()->user()->mobile . ' ثبت گردید و به اپراتور' . $operator_users->id . ' منتقل شد';
        $meta = [
            "description" => $request->description,
            "extra_number" => $request->extra_number,
            "address" => $user_address,
        ];
        $time=$request->time . " " . $request->timePicker;
        return OrderService::query()->create([
            'description' => $request->region_id,
            'extra_number' => $request->extra_number,
            'time_todo' => $time,
            'meta' => $meta,
            'code' => $code,
            'answers' => $answers,
            'price' => $price,
            'reports' => reportOrder($message, [$operator_users->id]),
            'region_id' => $user_address["region_id"],
            'service_id' => $service->id,
            'user_id' => request()->user()->id,
            'operator_id' => $operator_users->id,
            'media_id' => $idMedia,
        ]);

    }

    public function address_store_frontend($request,$user=null)
    {

        if(!$user){
            $user = auth()->user();
        }
        $region = (new RegionRepo())->findById($request->region_id);
        $oldAddress = $user->address;
        $timeNow = time();
        $oldAddress[$timeNow] = [
            'region_id' => $request->region_id,
            'region_name' => $region->name,
            'city_id' => $region->city->id,
            'city_name' => $region->city->name,
            'zip_code' => $request->zip_code,
            'address' => $request->address,
            'lat' => $request->lat,
            'long' => $request->long,
            'phone' => $request->phone,
            'mobile' => $request->mobile
        ];
        $user->update([
            'address' => $oldAddress,
        ]);
        return array($user->address[$timeNow],$timeNow);
    }

    public function all_orders_service_with($request, array $with = ['service', 'user', 'region', 'media', 'cancel_order'])
    {

        $user = auth()->user();
        $query = OrderService::query()->with($with);
        if ($user->hasPermissionTo(Permission::PERMISSION_ORDER_SERVICE_OPERATOR)) {
            $query->where('operator_id', $user->id);
        }
        elseif ($user->hasPermissionTo(Permission::PERMISSION_SUPER_ADMIN) || $user->hasPermissionTo(Permission::PERMISSION_ACCESS_ALL_ORDER_SERVICE)) {

            if ($request->expert_id) $query->where('expert_id', $request->expert_id);
            if ($request->operator_id) $query->where('operator_id', $request->operator_id);
            if ($request->team_leader_id) $query->where('team_leader_id', $request->team_leader_id);

        }

        elseif ($user->hasPermissionTo(Permission::PERMISSION_ORDER_SERVICE_FACTOR)) {
            $query->whereIn('status', [OrderService::WAITING_PAYMENT, OrderService::CHECK_FACTOR]);
        }

        if ($user->hasPermissionTo(Permission::PERMISSION_TEAM_LEADER)) {
            $query->where('team_leader_id', $user->id);
//                ->TimeAccess24HourAgo()
        }
        if ($user->hasPermissionTo(Permission::PERMISSION_EXPERT)) {
            $query->where('expert_id', $user->id)->TimeAccess24HourAgo();
        }

        if ($request->status) $query->where('status', $request->status);
        if ($request->code) $query->where('code', 'like', "%" . $request->code . "%");
        if ($request->start_day) $query->whereDate('created_at', '<=', $request->start_day);
        if ($request->end_day) $query->whereDate('created_at', '>=', $request->end_day);
        if ($request->mobile) $query->whereHas('user', function ($query) use ($request) {
            $query->where('mobile', $request->mobile);
        });
        if ($request->service) $query->whereHas('service', function ($query) use ($request) {
            $query->where('name', 'like', '%' . $request->service . '%');
        });


        return $query->orderBy('created_at', 'desc')->paginate();
    }

    public function show_order_detail_with_service($orderServiceID)
    {
        $user = auth()->user();
        $order = OrderService::query();
        if ($user->hasPermissionTo(Permission::PERMISSION_TEAM_LEADER)) {
            return $order
                ->TimeAccess24HourAgo()
                ->findOrFail($orderServiceID);
        }
        if ($user->hasPermissionTo(Permission::PERMISSION_MANAGE_EXPERT)) {
            return $order
                ->TimeAccess24HourAgo()
                ->findOrFail($orderServiceID);
        }
        return $order->findOrFail($orderServiceID);
    }

    public function findByID_with_region($Id)
    {
        return OrderService::query()->with(['region', 'service:name,id'])->findOrFail($Id);
    }

    public function findByID($Id)
    {
        return OrderService::query()->findOrFail($Id);
    }

    public function findForRateToOrder($orderId){
         return OrderService::query()
            ->where('id',$orderId)
            ->where('user_id',auth()->id())
            ->where('status',OrderService::DONE_AND_WAITING_FEEDBACK_FOR_EXPERT)
            ->firstOrFail();
    }


    public function findAndRateToOrder($request ,$order){

         $order->update([
                'status' => OrderService::DONE,
            ]);

        auth()->user()->update([
            'name' => $request->name
        ]);

        return $order->service_comment()->create([
            'user_id' => auth()->id(),
            'expert_id' => $order->expert_id,
            'service_id' => $order->service_id,
            'order_id' => $order->id,
            'content' => $request->content,
            'rate' => $request->rate,
        ]);
    }


    public function check_has_cancel_pending($order)
    {
        return $order
            ->cancel_order
            ->where('status', \Mehrab\OrderService\Models\CancelOrdersService::PENDING)
            ->first();
    }

    public function findByID_check_doesnt_have_team_leader($Id)
    {
        return OrderService::query()
            ->TimeAccess24HourLater()
            ->where('team_leader_id', null)
            ->findOrFail($Id);
    }

    public function findByID_check_all_order_service_manager_can_cancel($Id)
    {
        return OrderService::query()
            ->TimeAccess24HourLater()
            ->whereIn('status', [OrderService::SUSPENDED, OrderService::PENDING_OPERATOR, OrderService::PENDING_TEAM_LEADER, OrderService::PENDING_EXPERT])
            ->findOrFail($Id);
    }

    public function approved_all_cancel_pending($order)
    {

        if ($order->cancel_order()->exists()) {
            return $order->cancel_order()
                ->where('status', CancelOrdersService::PENDING)
                ->update([
                    'status' => CancelOrdersService::FINAL_APPROVAL,
                    'approved_by' => auth()->id(),
                    'pending_on' => Permission::PERMISSION_ACCESS_ALL_ORDER_SERVICE
                ]);
        } else {
            return true;
        }
    }

    public function findByID_check_order_has_pending_cancel_by_operator($id)
    {
        return OrderService::query()
            ->TimeAccess24HourLater()
            ->whereHas('cancel_order', function ($query) {
                $query->where('status', \Mehrab\OrderService\Models\CancelOrdersService::PENDING)
                    ->where('pending_on', Permission::PERMISSION_ORDER_SERVICE_OPERATOR);
            })
            ->where('operator_id', auth()->id())
            ->with('cancel_order')
            ->findOrFail($id);

    }

    public function findByID_check_order_has_pending_cancel_by_team_leader($id)
    {
        return OrderService::query()
            ->TimeAccess24HourAgo()
            ->TimeAccess24HourLater()
            ->whereHas('cancel_order', function ($query) {
                $query->where('status', \Mehrab\OrderService\Models\CancelOrdersService::PENDING)
                    ->where('pending_on', Permission::PERMISSION_TEAM_LEADER);
            })->where('team_leader_id', auth()->id())
            ->with('cancel_order')
            ->findOrFail($id);

    }

    public function findByID_check_all_order_service_manager_can_change_team_leader($id)
    {
        return OrderService::query()
            //->TimeAccess24HourLater()
            ->whereIn('status', [OrderService::SUSPENDED, OrderService::PENDING_EXPERT, OrderService::PENDING_TEAM_LEADER, OrderService::PENDING_OPERATOR])
            ->where('team_leader_id', "!=", null)
            ->orWhere(function ($query){
                $query->where('status',OrderService::SUSPENDED)
                    ->where('team_leader_id',null);
            })
            ->with('cancel_order')
            ->findOrFail($id);

    }

    public function change_team_leader_by_all_order_service_store($order, $team_leader_ID, $operator_message)
    {
        $order->cancel_order()
            ->where('status', CancelOrdersService::PENDING)
            ->update([
                'status' => CancelOrdersService::CONTINUE,
                'approved_by' => auth()->id(),
                'pending_on' => 'manage all orders service',
            ]);
        $report = $order->reports;
        $message = 'سرتیم این سفارش تغییر یافت و توسط مدیر سفارشات خدمات ' . auth()->id() . ' به سرتیم ' . $team_leader_ID . ' منتقل شد';

        $report[time()] =
            [
                "message" => $message,
                "type" => null,
                "id_watchers" => [$team_leader_ID, $order->operator_id],
            ];

        if ($operator_message) {
            $report[time() + 100] = [
                "message" => "یادداشت برای سرتیم : " . $operator_message,
                "type" => null,
                "id_watchers" => [$team_leader_ID, $order->operator_id],
            ];
        }
        return $order->update([
            'reports' => $report,
            'status' => OrderService::PENDING_TEAM_LEADER,
            'team_leader_id' => $team_leader_ID,
            'expert_id' => null,
        ]);
    }

    public function findByID_check_doesnt_have_expert($Id)
    {
        return OrderService::query()
            ->TimeAccess24HourAgo()
            ->TimeAccess24HourLater()
            ->with(['service', 'region'])
            ->where('expert_id', null)
            ->findOrFail($Id);
    }

    public function findByID_check_order_status_be_expert($Id)
    {
        return OrderService::query()
            ->TimeAccess24HourAgo()
            ->TimeAccess24HourLater()
            ->where('status', OrderService::PENDING_EXPERT)
            ->findOrFail($Id);
    }

    public function findByID_check_order_status_be_accept_expert($Id)
    {
        return OrderService::query()
           // ->TimeAccess24HourAgo()
          //  ->TimeAccess24HourLater()
           // ->where('status', OrderService::ACCEPT_EXPERT)
            ->findOrFail($Id);
    }

    public function findByID_check_order_status_be_doing($Id)
    {
        return OrderService::query()
            ->with('service')
//            ->TimeAccess24HourAgo()
//            ->TimeAccess24HourLater()
            //->where('status', OrderService::DOING)
            ->findOrFail($Id);
    }

    public function findByID_check_order_status_be_related_factor_admin($Id)
    {
        return OrderService::query()
            ->with('service')
//            ->TimeAccess24HourAgo()
//            ->TimeAccess24HourLater()
            ->whereIn('status', [OrderService::WAITING_PAYMENT, OrderService::CHECK_FACTOR])
            ->findOrFail($Id);
    }

    public function accept_order_by_expert($request, $order_service)
    {
        //todo send sms to user that your order accepted by this expert
        return true;
    }

    public function start_work($order)
    {
        $meta = $order->meta;
        $meta['start_work'] = time();
        return $order->update([
            'status' => OrderService::DOING,
            'meta' => $meta,
        ]);
    }

    public function choose_team_leader_store($order, $team_leader_ID, $operator_message)
    {
        $report = $order->reports;
        $operatorID = $order->operator_id;

        if (auth()->user()->hasAnyPermission([Permission::PERMISSION_ORDER_SERVICE_OPERATOR])) {
            $newReport = 'این سفارش توسط اپراتور ' . $operatorID . ' به سرتیم ' . $team_leader_ID . ' منتقل شد';
        } else {
            $newReport = 'این سفارش توسط مدیر سفارش ' . auth()->id() . ' به سرتیم ' . $team_leader_ID . ' منتقل شد';
        }
        $report[time()] = $this->make_report(null, $newReport, [$team_leader_ID, $operatorID]);

        if ($operator_message) {
            $report[time() + 100] = $this->make_report(null, "یادداشت برای سرتیم : " . $operator_message, [$team_leader_ID, $operatorID]);
        }
        return $order->update([
            'reports' => $report,
            'status' => OrderService::PENDING_TEAM_LEADER,
            'team_leader_id' => $team_leader_ID,
        ]);
    }

    public function change_team_leader_store($order, $team_leader_ID, $operator_message)
    {
        $order->cancel_order()
            ->where('status', CancelOrdersService::PENDING)
            ->update([
                'status' => CancelOrdersService::CONTINUE,
                'approved_by' => auth()->id(),
            ]);
        $report = $order->reports;
        $message = 'سرتیم این سفارش تغییر یافت و توسط اپراتور ' . auth()->id() . ' به سرتیم ' . $team_leader_ID . ' منتقل شد';

        $report[time()] =
            [
                "message" => $message,
                "type" => null,
                "id_watchers" => [$team_leader_ID, auth()->id()],
            ];

        if ($operator_message) {
            $report[time() + 100] = [
                "message" => "یادداشت اپراتور برای سرتیم : " . $operator_message,
                "type" => null,
                "id_watchers" => [$team_leader_ID, auth()->id()],
            ];
        }
        return $order->update([
            'reports' => $report,
            'status' => OrderService::PENDING_TEAM_LEADER,
            'team_leader_id' => $team_leader_ID,
            'expert_id' => null,
        ]);
    }

    public function change_expert_store($order, $expertID, $team_leader_message)
    {
        $order->cancel_order()->update([
            'status' => CancelOrdersService::CONTINUE,
            'approved_by' => auth()->id(),
        ]);
        $report = $order->reports;
        $message = 'متخصص این سفارش تغییر یافت و توسط سرتیم ' . auth()->id() . ' به متخصص ' . $expertID . ' منتقل شد';

        $report[time()] =
            [
                "message" => $message,
                "type" => null,
                "id_watchers" => [$expertID, $order->opertor_id, auth()->id()]
            ];

        if ($team_leader_message) {
            $report[time() + 100] = [
                "message" => "یادداشت سرتیم برای متخصص : " . $team_leader_message,
                "type" => null,
                "id_watchers" => [$expertID, $order->opertor_id, auth()->id()]
            ];
        }
        return $order->update([
            'reports' => $report,
            'status' => OrderService::PENDING_EXPERT,
            'expert_id' => $expertID,
        ]);
    }

    public function choose_expert_store($order, $expertID, $operator_message)
    {
        $report = $order->reports;
        $message = 'این سفارش توسط سرتیم ' . auth()->id() . ' به متخصص ' . $expertID . ' منتقل شد';

        $report[time()] =
            [
                "message" => $message,
                "type" => null,
                "id_watchers" => [$expertID, $order->operator_id, auth()->id()],
            ];

        if ($operator_message) {
            $report[time() + 100] = [
                "message" => "یادداشت سرتیم برای متخصص : " . $operator_message,
                "type" => null,
                "id_watchers" => [$expertID, $order->operator_id, auth()->id()],
            ];
        }
        return $order->update([
            'reports' => $report,
            'status' => OrderService::PENDING_EXPERT,
            'expert_id' => $expertID,
        ]);
    }

    public function update_reports($order, $status, $type, $message, array $id_watchers = [])
    {
        $reports = $order->reports;
        $reports[time()] = [
            'message' => $message,
            'type' => $type,
            "id_watchers" => $id_watchers
        ];
        return $order->update([
            'reports' => $reports,
            'status' => $status,
        ]);
    }

    public function make_report($type, $message, array $id_watchers = [])
    {
        return [
            'message' => $message,
            'type' => $type,
            "id_watchers" => $id_watchers
        ];
    }

    public function end_work_order_by_expert($order)
    {
        $meta = $order->meta;
        $meta['end_work'] = time();
        $meta['end_role'] = Permission::PERMISSION_EXPERT ?? null;
        $meta['end_id'] = auth()->id();
        return $order->update([
            'meta' => $meta
        ]);
    }

    public function end_work_order_by_expert_set_factor($final_price, $factor, $order,$description)
    {
        $meta = $order->meta;
        $meta['factor'] = $factor;
        $meta['end_work'] = time();
        $meta['end_role'] = Permission::PERMISSION_EXPERT ?? null;
        $meta['end_id'] = auth()->id();
        $meta['message_factor'] = $description;
        return $order->update([
            'meta' => $meta,
            'price' => $final_price,
        ]);
    }

    public function end_work_order_by_order_admin_set_factor($request, $order)
    {
        $meta = $order->meta;
        if(!is_null($request->data)){
            $meta['factor'] = $request->data;
        }

        $meta['end_role'] = Permission::PERMISSION_ORDER_SERVICE_FACTOR ?? null;
        $meta['end_id'] = auth()->id();
        return $order->update([
            'meta' => $meta,
            'price' => $request->price_final>0? $request->price_final:$order->price,
        ]);
    }

    public function send_to_supporter_set_factor($description, $order)
    {
        $meta = $order->meta;
        $meta['end_work'] = time();
        $meta['message_factor'] = $description;
//        $meta['end_role'] = Permission::PERMISSION_EXPERT ?? null;
//        $meta['end_id'] = auth()->id();
        return $order->update([
            'meta' => $meta,
        ]);
    }

    public function doneOrderService(OrderService $order)
    {
        return $order->update([
            'status' => OrderService::DONE_AND_WAITING_FEEDBACK_FOR_EXPERT,
        ]);
    }

    public function findUserOrders($user=null)
    {
        if(!$user){
            $user = auth()->user();
        }

        return OrderService::query()
            ->with('service')
            ->where('user_id',$user->id)
            ->paginate();
    }
    public function findUserOrdersNotPaginate($user=null)
    {
        if(!$user){
            $user = auth()->user();
        }

        return OrderService::query()
            ->with('service')
            ->where('user_id',$user->id)
            ->orderByDesc("created_at")
            ->get();
    }
    public function findUserOrder($orderId)
    {
        $user = auth()->user();
        return OrderService::query()
            ->where('user_id',$user->id)
            ->findOrFail($orderId);
    }
    public function findUserOrderCount()
    {
        $user = auth()->user();
        return OrderService::query()
            ->where('user_id',$user->id)
            ->count();
    }
    public function findUserCancelOrderCount()
    {
        $user = auth()->user();
        return OrderService::query()
            ->where('user_id',$user->id)
            ->where('status',OrderService::CANCELED)
            ->count();
    }

    public function doingOrderCount()
    {
        $user = auth()->user();
        return OrderService::query()
            ->where('user_id',$user->id)
            ->whereNotIn('status',[OrderService::CANCELED,OrderService::SUSPENDED,OrderService::DONE,OrderService::DONE_AND_WAITING_FEEDBACK_FOR_EXPERT])
            ->count();
    }

    public function cancelOrderServiceByUser($request,$orderId)
    {
        $order = OrderService::query()
            ->canUserCancelOrder()
            ->where('id',$orderId)
            ->where('user_id',$request->user()->id)
            ->firstOrFail();

        $reports = $order->reports ;

        $reports[time()] = [
            'message' => $request->content,
            'type' => 'suspended',
            "id_watchers" => [$order->operator_id ?? '', $order->team_leader_id ?? '' , $order->expert_id ?? '' ]
        ];

        $order->update([
            'status' => OrderService::SUSPENDED,
            'reports' => $reports,
        ]);

       return  $order->cancel_order()->create([
            'user_id' =>$request->user()->id,
            'orderServices_id' => $order->id,
            'role' => Permission::PERMISSION_USER,
            'description' => $request->content,
            'pending_on' => Permission::PERMISSION_ORDER_SERVICE_OPERATOR,
            'status' => CancelOrdersService::PENDING,
        ]);
    }

    public function getAllCount()
    {
        return OrderService::query()->count();
    }

    public function getOrderServiceByPeriod($start, $end)
    {
        return OrderService::query()
            ->whereDate('created_at', '<=', $start)
            ->whereDate('created_at', '>=', $end)
            ->count();
    }

    public function getOrdersByDays($date)
    {
        return OrderService::query()
            ->whereDate('created_at', $date)
            ->count();
    }

    public function getDailySummery(\Illuminate\Support\Collection $dates, $seller_id = null)
    {
        $query = OrderService::query()
            ->where('created_at', '>', $dates->keys()->first())
            ->groupBy('date')
            ->orderBy('date');
//
//        if (!is_null($seller_id)) {
//            $query->where('seller_id', $seller_id);
//        }

        return $query->get([
            DB::raw('DATE(created_at) as date'),
            DB::raw('COUNT(id) as total'),
        ]);

    }

    public function getAllActiveOperatorCount($user_id)
    {
        return OrderService::query()
            ->timeAccess24HourLater()
            ->where('operator_id',$user_id)
            ->where('status',OrderService::PENDING_OPERATOR)
            ->count();
    }

    public function allOrdersCancelRequestOperator($user_id)
    {
        return OrderService::query()
            ->timeAccess24HourLater()
            ->where('operator_id',$user_id)
            ->whereHas('cancel_order',function ($query){
                $query->where('pending_on',Permission::PERMISSION_ORDER_SERVICE_OPERATOR)
                ->where('status',CancelOrdersService::PENDING);
            })
            ->count();
    }

    public function getAllActiveOperatorNotFinalApprovedCount(?int $user_id)
    {
        return CancelOrdersService::query()
            ->where('approved_by',$user_id)
            ->count();
    }

    public function all_orders_operator(?int $user_id)
    {
        return OrderService::query()
            ->where('operator_id',$user_id)
            ->count();
    }

    public function all_orders_team_leader(?int $user_id)
    {
        return OrderService::query()
            ->where('team_leader_id',$user_id)
            ->count();
    }

    public function getAllActiveTeamLeaderCount($user_id)
    {
        return OrderService::query()
            ->timeAccess24HourLater()
            ->timeAccess24HourAgo()
            ->where('team_leader_id',$user_id)
            ->where('status',OrderService::PENDING_TEAM_LEADER)
            ->count();
    }

    public function allOrdersCancelRequestTeamLeader($user_id)
    {
        return OrderService::query()
            ->timeAccess24HourLater()
            ->where('team_leader_id',$user_id)
            ->whereHas('cancel_order',function ($query){
                $query->where('pending_on',Permission::PERMISSION_TEAM_LEADER)
                    ->where('status',CancelOrdersService::PENDING);
            })
            ->count();
    }

    public function getAllOrdersInQueueTeamLeader($user_id){
        return OrderService::query()
            ->where('time_todo', '>', Carbon::now()->addHour('24'))
            ->where('team_leader_id',$user_id)
            ->where('status',OrderService::PENDING_TEAM_LEADER)
            ->count();
    }

    public function all_orders_teamLeader(?int $user_id)
    {
        return OrderService::query()
            ->where('team_leader_id',$user_id)
            ->count();
    }


    public function getAllActiveExpertCount($user_id)
    {
        return OrderService::query()
            ->timeAccess24HourLater()
            ->timeAccess24HourAgo()
            ->where('expert_id',$user_id)
            ->where('status',OrderService::PENDING_TEAM_LEADER)
            ->count();
    }

    public function allOrdersCancelRequestExpert($user_id)
    {
        return OrderService::query()
            ->timeAccess24HourLater()
            ->where('expert_id',$user_id)
            ->whereHas('cancel_order',function ($query){
                $query->where('pending_on',Permission::PERMISSION_EXPERT)
                    ->where('status',CancelOrdersService::PENDING);
            })
            ->count();
    }

    public function getAllOrdersInQueueExpert($user_id){
        return OrderService::query()
            ->where('time_todo', '>', Carbon::now()->addHour('24'))
            ->where('expert_id',$user_id)
            ->where('status',OrderService::PENDING_EXPERT)
            ->count();
    }

    public function all_orders_Expert(?int $user_id)
    {
        return OrderService::query()
            ->where('expert_id',$user_id)
            ->count();
    }

}
