<?php

namespace App\Http\Controllers;

use App\Models\HumanResource;
use Log;
use Illuminate\Http\Request;
use App\Models\Presence;
use App\Models\ReportK3;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;

class PresenceController extends Controller
{
    public function add(Request $request)
    {
        $this->validate($request, [
            'user_id' => 'required'
        ]);

        $checkLocation = $this->checkLocation($request);
        $statusBoundary = false;
        $date = date_create($request->clock_time);
        // assign and in boundary
        if(count($checkLocation) > 0 && $checkLocation[0]['boundary']){
            $statusBoundary = true;
        }
        $statusRestriction = HumanResource::select('status_boundary')->where('id', $request->user_id)->first();
        if (!$statusRestriction->status_boundary) {
            $statusBoundary = true;
        }
        // not assign
        if(!$checkLocation[0]['status_assign'] && $checkLocation[0]['boundary'] == false && $statusBoundary == false){
            $data=array(
                'id'        => null,
                'boundary'  => $statusBoundary
            );
            return response()->json(['status'=>'failed', 'data'=>$data, 'message'=>'Tidak dapat melakukan presensi. Anda belum di assign ke area kerja.','code'=>200], 200);
        }
        // assign and not in boundary
        if($checkLocation[0]['status_assign'] && $checkLocation[0]['boundary'] == false && $statusBoundary == false){
            $data=array(
                'id'        => null,
                'boundary'  => true
            );
            return response()->json(['status'=>'failed', 'data'=>$data, 'message'=>'Tidak dapat melakukan presensi. Anda berada di luar area kerja.','code'=>200], 200);
        }

        if($request->type=="out"){
            $clock_out_loc = $this->getLoc($request->clock_out_lat, $request->clock_out_lng)->display_name;
            $dataUpdate = array(
                "clock_out"=>$request->clock_time,
                "clock_out_lat" => $request->clock_out_lat,
                "clock_out_lng" => $request->clock_out_lng,
                "updated_by"=>$this->currentName,
                "clock_out_loc" => $clock_out_loc,
                "clock_out_boundary" => $statusBoundary
            );

            $resultUpdate = $this->updateFormAdd($dataUpdate, $request->user_id);
            if($resultUpdate && $resultUpdate > 0){
                if($statusBoundary){
                    for ($i=0; $i < count($checkLocation); $i++) {
                        # code...
                        DB::table('clock_in_out_boundary')->insert([
                            "clock_in_out_id"   => $resultUpdate,
                            "user_id"           => $request->user_id,
                            "activity_id"       => $checkLocation[$i]['activity_id'] ? $checkLocation[$i]['activity_id'] : 0,
                            "type"              => $request->type,
                            "created_at"        => $date,
                            "created_by"        => $this->currentName
                        ]);
                    };
                };
                $data=array(
                    'id'        => $resultUpdate,
                    'boundary'  => $statusBoundary
                );

                return response()->json(['status'=>'success', 'data'=>$data,'message'=>'clock out success!','code'=>200], 200);
            }
            else{
                return response()->json(['status'=>'failed','message'=>'clock out failed please try again!','code'=>400], 400);
            }
            die();
        }

        $onlyDate = date_format($date,"Y-m-d");
        // $clock_in_loc = $this->getLoc($request->clock_in_lat, $request->clock_in_lng)->display_name;
        $clock_in_loc = "test";

        $dataAdd = array(
            'user_id'=> $request->user_id,
            'clock_in'=> $request->clock_time,
            'date_presence'=> $onlyDate,
            'created_by' => $this->currentName,
            'clock_in_lat' => $request->clock_in_lat,
            'clock_in_lng' => $request->clock_in_lng,
            'clock_in_loc' => $clock_in_loc,
            'clock_in_boundary' => $statusBoundary
        );

        $result = Presence::create($dataAdd);
        $data=array(
            'id'        => $result->id,
            'boundary'  => $statusBoundary
        );
        if($result){
            if($statusBoundary){
                for ($i=0; $i < count($checkLocation); $i++) {
                    # code...
                    DB::table('clock_in_out_boundary')->insert([
                        "clock_in_out_id"   => $result->id,
                        "user_id"           => $request->user_id,
                        "activity_id"       => $checkLocation[$i]['activity_id'],
                        "type"              => $request->type,
                        "created_at"        => $date,
                        "created_by"        => $this->currentName
                    ]);
                };
            };
            return response()->json(['status'=>'success', 'data' => $data,'message'=>'clock in successfully!','code'=>200], 200);
        }else{
            return response()->json(['status'=>'failed','message'=>'clock in failed!','code'=>400], 400);
        }
    }

    public function reportK3(Request $request){
        // return response()->json(['status'=>'success', 'message'=>$request->report_k3['detail'],'code'=>200], 200);

        $this->validate($request, [
            'user_id' => 'required'
        ]);

        $checkLocation = $this->checkLocation($request);
        $statusBoundary = false;
        $date = date_create($request->time);
        $statusRestriction = HumanResource::select('status_boundary')->where('id', $request->user_id)->first();
        // assign and in boundary
        if (count($checkLocation) > 0 && $statusRestriction->status_boundary == true)
        {
            if ($checkLocation[0]['boundary'] == true)
            {
                $statusBoundary = true;
            } else {
                $statusBoundary = false;
            }
        }
        // assign and not in boundary or in boundary
        else {
            if ($checkLocation[0]['boundary'] == true || $checkLocation[0]['boundary'] == false)
            {
                $statusBoundary = true;
            }
        }
        // not assign
        if(!$checkLocation[0]['status_assign'] && $checkLocation[0]['boundary'] == false && $statusBoundary == false){
            $data=array(
                'id'        => null,
                'boundary'  => $statusBoundary
            );
            return response()->json(['status'=>'failed', 'data'=>$data, 'message'=>'Tidak dapat melakukan presensi. Anda belum di assign ke area kerja.','code'=>200], 200);
        }
        // assign and not in boundary
        if($checkLocation[0]['status_assign'] && $checkLocation[0]['boundary'] == false && $statusBoundary == false){
            $data=array(
                'id'        => null,
                'boundary'  => true
            );
            return response()->json(['status'=>'failed', 'data'=>$data, 'message'=>'Tidak dapat melakukan presensi. Anda berada di luar area kerja.','code'=>200], 200);
        }

        if($request->clock_in_out['type']=="out"){
            $clock_out_loc = $this->getLoc($request->clock_in_out['clock_out_lat'], $request->clock_in_out['clock_out_lng'])->display_name;
            $dataUpdate = array(
                "clock_out"=>$request->time,
                "clock_out_lat" => $request->clock_in_out['clock_out_lat'],
                "clock_out_lng" => $request->clock_in_out['clock_out_lng'],
                "updated_by"=>$this->currentName,
                "clock_out_loc" => $clock_out_loc,
                "clock_out_boundary" => $statusBoundary
            );

            $resultUpdate = $this->updateFormAdd($dataUpdate, $request->user_id);
            if($resultUpdate && $resultUpdate > 0){
                if($statusBoundary){
                    for ($i=0; $i < count($checkLocation); $i++) {
                        # code...
                        DB::table('clock_in_out_boundary')->insert([
                            "clock_in_out_id"   => $resultUpdate,
                            "user_id"           => $request->user_id,
                            "activity_id"       => $checkLocation[$i]['activity_id'] ? $checkLocation[$i]['activity_id'] : 0,
                            "type"              => $request->clock_in_out['type'],
                            "created_at"        => $date,
                            "created_by"        => $this->currentName
                        ]);
                    };
                };
                $data=array(
                    'presence_id'        => $resultUpdate,
                    'boundary'  => $statusBoundary
                );

                return response()->json(['status'=>'success', 'data'=>$data,'message'=>'clock out success!','code'=>200], 200);
            }
            else{
                return response()->json(['status'=>'failed','message'=>'clock out failed please try again!','code'=>400], 400);
            }
            die();
        }

        $onlyDate = date_format($date,"Y-m-d");
        $clock_in_loc = $this->getLoc($request->clock_in_out['clock_in_lat'], $request->clock_in_out['clock_in_lng'])->display_name;

        $dataFormK3 = array(
            "user_id"       => $request->user_id,
            "proyek_id"     => $request->report_k3['proyek_id'],
            "report_date"   => $request->time,
            "description"   => $request->report_k3['description']
        );

        $dataFormPresence = array(
            'user_id'           => $request->user_id,
            'clock_in'          => $request->time,
            'date_presence'     => $onlyDate,
            'created_by'        => $this->currentName,
            'clock_in_lat'      => $request->clock_in_out['clock_in_lat'],
            'clock_in_lng'      => $request->clock_in_out['clock_in_lng'],
            'clock_in_loc'      => $clock_in_loc,
            'clock_in_boundary' => $statusBoundary
        );

        $result = Presence::create($dataFormPresence);
        $data=array(
            'presence_id'       => $result->id,
            'boundary'          => $statusBoundary
        );
        if($result){
            if($statusBoundary){
                $insertk3 = $this->insertK3($dataFormK3, $request->report_k3['detail']) ;
                for ($i=0; $i < count($checkLocation); $i++) {
                    # code...
                    DB::table('clock_in_out_boundary')->insert([
                        "clock_in_out_id"   => $result->id,
                        "user_id"           => $request->user_id,
                        "activity_id"       => $checkLocation[$i]['activity_id'] ? $checkLocation[$i]['activity_id'] : 0,
                        "type"              => $request->type,
                        "created_at"        => $date,
                        "created_by"        => $this->currentName
                    ]);
                };
                $data['report_id'] = $insertk3->id;
            };
            return response()->json(['status'=>'success', 'data'=> $data, 'message'=>'clock in successfully!','code'=>200], 200);
        }else{
            return response()->json(['status'=>'failed','message'=>'clock in failed!','code'=>400], 400);
        }
    }

    private function insertK3($params, $details){
        $insert = ReportK3::create($params);
        if($insert && $details){
            $this->addDetailK3($details, $insert->id);
        }
        return $insert;
    }

    private function checkLocation($params){
        // cek user tersebut apakah punya assign task yang ada bondary nya
        // geom ada di table activity
        // $clock_time =
        $user = HumanResource::find($params->user_id);
        $geomQuery = DB::table("assign_hr_to_activity as ahta")->select("ma.geom", "ma.id")
            ->join("m_activity as ma", "ma.id", "=", "ahta.activity_id")
            ->where("ahta.user_id", $params->user_id)
            ->whereNotNull("ma.geom")
            ->whereDate("ma.start_date", "<=", $params->time)
            ->whereDate("ma.end_date", ">=", $params->time);
        if (isset($params->report_k3['proyek_id'])) {
            $geom = $geomQuery->where("ma.proyek_id", $params->report_k3['proyek_id'])->get();
        } else {
            $geom = $geomQuery->get();
        }
        $temp = [];
        if (count($geom) > 0) {
            foreach($geom as $dataGeom){
                $valGeom = json_decode($dataGeom->geom);
                if($params->clock_in_out['type']=="out"){
                    if($valGeom->type == "FeatureCollection"){
                        $multiArea = $valGeom->features;
                        foreach($multiArea as $area){
                            if ($area->geometry->type === "Point") {
                                $pointCoordinates = $area->geometry->coordinates;
                                $pointLng = $pointCoordinates[0];
                                $pointLat = $pointCoordinates[1];

                                $check = DB::select(DB::raw("SELECT ST_Distance(
                                    ST_GeomFromGeoJSON('" . json_encode($area->geometry) . "'),
                                    ST_GeomFromText('POINT(" . $params->clock_in_out['clock_in_lng'] . " " . $params->clock_in_out['clock_in_lat'] . ")', 4326)
                                ) <= " . $area->properties->radius . " as within_radius"));

                                if ($check[0]->within_radius) {
                                    break;
                                }
                            }
                            $check = DB::select(DB::raw("SELECT ST_Intersects(ST_GeomFromGeoJSON('".json_encode($area->geometry)."'),
                            ST_GeomFromText('POINT(".$params->clock_in_out['clock_out_lng']." ".$params->clock_in_out['clock_out_lat'].")', 4326)) as boundary"));
                            if($check[0]->boundary){
                                break;
                            }
                        }
                    }else{
                        $check = DB::select(DB::raw("SELECT ST_Intersects(ST_GeomFromGeoJSON('".json_encode($valGeom->geometry)."'),
                                        ST_GeomFromText('POINT(".$params->clock_in_out['clock_out_lng']." ".$params->clock_in_out['clock_out_lat'].")', 4326)) as boundary"));
                    }
                }else{
                    if($valGeom->type == "FeatureCollection"){
                        $multiArea = $valGeom->features;
                        foreach($multiArea as $area){
                            if ($area->geometry->type === "Point") {
                                $pointCoordinates = $area->geometry->coordinates;
                                $pointLng = $pointCoordinates[0];
                                $pointLat = $pointCoordinates[1];

                                $check = DB::select(DB::raw("SELECT ST_Distance(
                                    ST_GeomFromGeoJSON('" . json_encode($area->geometry) . "'),
                                    ST_GeomFromText('POINT(" . $params->clock_in_out['clock_in_lng'] . " " . $params->clock_in_out['clock_in_lat'] . ")', 4326)
                                ) <= " . $area->properties->radius . " as within_radius"));

                                if ($check[0]->within_radius) {
                                    break;
                                }
                            }
                            $check = DB::select(DB::raw("SELECT ST_Intersects(ST_GeomFromGeoJSON('".json_encode($area->geometry)."'),
                                        ST_GeomFromText('POINT(".$params->clock_in_out['clock_in_lng']." ".$params->clock_in_out['clock_in_lat'].")', 4326)) as boundary"));
                            if($check[0]->boundary){
                                break;
                            }
                        }
                    }else{
                        $check = DB::select(DB::raw("SELECT ST_Intersects(ST_GeomFromGeoJSON('".json_encode($valGeom->geometry)."'),
                                        ST_GeomFromText('POINT(".$params->clock_in_out['clock_in_lng']." ".$params->clock_in_out['clock_in_lat'].")', 4326)) as boundary"));
                    }
                }
                if(!$user->status_boundary || count($check)>0){
                    if(!$user->status_boundary || (isset($check[0]->boundary) && $check[0]->boundary)){
                        $temp[]=array(
                            "activity_id"   => $dataGeom->id,
                            "boundary"      => $check[0]->boundary,
                            "status_assign" => true
                        );
                    } else if (!$user->status_boundary || (isset($check[0]->within_radius) && $check[0]->within_radius)) {
                        $temp[]=array(
                            "activity_id"   => $dataGeom->id,
                            "boundary"      => $check[0]->within_radius,
                            "status_assign" => true
                        );
                    }
                } else {
                    // bypass work area restriction
                    $temp[]=array(
                        "activity_id"   => null,
                        "boundary"      => true,
                        "status_assign" => true
                    );
                }
            }
            // assign and not in boundary
            if(count($temp) < 1){
                $temp[]=array(
                    "activity_id"   => null,
                    "boundary"      => false,
                    "status_assign" => true
                    // "geom" => $geom,
                    // "cek" => $check[0]->boundary
                );
            }
        }
        else{
            if ($user->status_boundary) {
                // bypass work area restriction
                $temp[]=array(
                    "activity_id"   => null,
                    "boundary"      => true,
                    "status_assign" => true
                );
            } else {
                // not assign
                $temp[]=array(
                    "activity_id"   => null,
                    "boundary"      => false,
                    "status_assign" => false
                );
            }
        }
        return $temp;
    }

    public function checkLocationTest(Request $request){
        // cek user tersebut apakah punya assign task yang ada bondary nya
        // geom ada di table activity
        // $clock_time =
        $params = $request;
        $geom = DB::table("assign_hr_to_activity as ahta")->select("ma.geom", "ma.id")
                    ->join("m_activity as ma", "ma.id", "=", "ahta.activity_id")
                    ->where("ahta.user_id", $params->user_id)
                    ->whereNotNull("ma.geom")
                    ->whereDate("ma.start_date", "<=", $params->time)
                    ->whereDate("ma.end_date", ">=", $params->time)
                    ->get();
        $temp = [];
        // return json_encode($geom);
        if (count($geom) > 0) {
            foreach($geom as $dataGeom){
                $valGeom = json_decode($dataGeom->geom);
                if($params->clock_in_out['type']=="out"){
                    if($valGeom->type == "FeatureCollection"){
                        // return count($valGeom->features);
                        $multiArea = $valGeom->features;
                        foreach($multiArea as $area){
                            $check = DB::select(DB::raw("SELECT ST_Intersects(ST_GeomFromGeoJSON('".json_encode($area->geometry)."'),
                            ST_GeomFromText('POINT(".$params->clock_in_out['clock_out_lng']." ".$params->clock_in_out['clock_out_lat'].")', 4326)) as boundary"));
                            if($check[0]->boundary){
                                break;
                            }
                        }
                    }else{
                        $check = DB::select(DB::raw("SELECT ST_Intersects(ST_GeomFromGeoJSON('".json_encode($valGeom->geometry)."'),
                                        ST_GeomFromText('POINT(".$params->clock_in_out['clock_out_lng']." ".$params->clock_in_out['clock_out_lat'].")', 4326)) as boundary"));
                    }
                }else{
                    if($valGeom->type == "FeatureCollection"){
                        // return count($valGeom->features);
                        $multiArea = $valGeom->features;
                        foreach($multiArea as $area){
                            $check = DB::select(DB::raw("SELECT ST_Intersects(ST_GeomFromGeoJSON('".json_encode($area->geometry)."'),
                                        ST_GeomFromText('POINT(".$params->clock_in_out['clock_in_lng']." ".$params->clock_in_out['clock_in_lat'].")', 4326)) as boundary"));
                            if($check[0]->boundary){
                                break;
                            }
                        }
                    }else{
                        $check = DB::select(DB::raw("SELECT ST_Intersects(ST_GeomFromGeoJSON('".json_encode($valGeom->geometry)."'),
                                        ST_GeomFromText('POINT(".$params->clock_in_out['clock_in_lng']." ".$params->clock_in_out['clock_in_lat'].")', 4326)) as boundary"));
                    }
                }
                if(count($check)>0){
                    if($check[0]->boundary){
                        $temp[]=array(
                            "activity_id"   => $dataGeom->id,
                            "boundary"      => $check[0]->boundary,
                            "status_assign" => true
                        );
                    }
                }
            }
            // assign and not in boundary
            if(count($temp) < 1){
                $temp[]=array(
                    "activity_id"   => null,
                    "boundary"      => false,
                    "status_assign" => true
                    // "geom" => $geom,
                    // "cek" => $check[0]->boundary
                );
            }
        }
        else{
            // not assign
            $temp[]=array(
                "activity_id"   => null,
                "boundary"      => false,
                "status_assign" => false
            );
        }
        return $temp;
    }

    public function edit($id){
        if(!$id || (int) $id < 0 || $id==""){
            return response()->json(['status'=>'failed','message'=>'id is required!','code'=>400], 400);
            die();
        }

        $result = Presence::find($id);

        if($result){
            return response()->json(['status'=>'success','code'=>200,'data'=>$result], 200);
        }else{
            return response()->json(['status'=>'failed','message'=>'failed get data project, please try again later!','code'=>400], 400);
        }
    }

    public function clockinout($id) {
        $dateTimeNow = Carbon::now()->addHour(7);
        $dataPresence = Presence::where('user_id', $id)->orderBy('id', 'DESC')->first();

        if($dataPresence){

                $dateNow = date("Y-m-d");
                $dateA = strtotime($dataPresence->clock_in);
                $dayClockin = date("Y-m-d", $dateA);
                if($dayClockin == $dateNow){
                    $clock_in = $dataPresence->clock_in;
                    $clock_out = $dataPresence->clock_out;
                }else{
                    $clock_in = null;
                    $clock_out = null;
                }
            $res_data = array(
                "id" => $dataPresence->id,
                "at" => $dateTimeNow,
                "user_id"=> $id,
                "clock_in"=> $clock_in,
                "clock_out"=> $clock_out,
                "last_clock_in"=> $dataPresence->clock_in,
                "last_clock_out"=> $dataPresence->clock_out,
                "in_working_time"=> true
            );
            return response()->json(['status'=>'success','data'=>$res_data,'code'=>200], 200);
        }
        $res_data = array(
            "id" => null,
            "at" => $dateTimeNow,
            "user_id"=> $id,
            "clock_in"=> null,
            "clock_out"=> null,
            "last_clock_in"=> null,
            "last_clock_out"=> null,
            "in_working_time"=> true
        );
        return response()->json(['status'=>'success','data'=>$res_data,'code'=>200], 200);
    }

    private function updateFormAdd($data, $id){
        $date = date_create($data['clock_out']);
        $onlyDate = date_format($date,"Y-m-d");

        $dataPresence = Presence::where('user_id',$id)
            ->where("clock_in", "<=", $data["clock_out"])
            ->orderByDesc("id")
            ->first();

        if($dataPresence){
            $queryUpdate = $dataPresence->update($data);
            if($queryUpdate){
                $getDataUpdate = Presence::where('user_id', $id)->where("date_presence", $onlyDate)->first();
                return $getDataUpdate->id;
            }else{
                return false;
            }
        }else{
            return false;
        }
        die();
    }

    public function update(Request $request, $id)
    {
        if(!$id || (int) $id < 0 || $id==""){
            return response()->json(['status'=>'failed','message'=>'id is required!','code'=>400], 400);
        }

        $data = Presence::find($id);

        if($data){
            $result = $data->update($request->all());
        }else{
            return response()->json(['status'=>'failed','message'=>'data presence not found!','code'=>400], 400);
            die();
        }

        if($result){
            return response()->json(['status'=>'success','message'=>'data presence successfully updated!','code'=>200], 200);
        }else{
            return response()->json(['status'=>'failed','message'=>'data presence  failed updated!','code'=>400], 400);
        }
    }

    public function delete($id)
    {
        $data = Presence::find($id);

        if($data){
            $delete = $data->delete();
        }else{
            return response()->json(['status'=>'failed','message'=>'data presence not found!','code'=>400], 400);
            die();
        }

        if($delete){
            return response()->json(['status'=>'success','message'=>'data presence successfully deleted!','code'=>200], 200);
        }else{
            return response()->json(['status'=>'failed','message'=>'data presence failed deleted!','code'=>400], 400);
        }
    }

    public function search(Request $request)
    {
        $payload = $request->all();
        $dataBuilder = $this->setUpPayload($payload, 't_clock_in_out');
        $builder = $dataBuilder['builder'];
        $countBuilder = $dataBuilder['count'];
        $dataGet = $builder->get();
        $totalRecord = $countBuilder->count();
        return response()->json(['status'=>'success','code'=>200,'data'=>$dataGet, 'totalRecord'=>$totalRecord], 200);
    }

    public function list()
    {
        $data = Presence::all();
        $countData = $data->count();

        if($data){
            return response()->json(['status'=>'success','code'=>200,'data'=>$data, 'totalRecord'=>$countData], 200);
        }else{
            return response()->json(['status'=>'failed','message'=>'failed get list presence, please try again later!','code'=>400], 400);
        }
    }

    public function bulkUpdateLocation()
    {
        $data = Presence::all();
        $finalData = [];
        foreach($data as $objRow) {
            $presence = Presence::find($objRow->id);

            $clock_in_lat = $objRow->clock_in_lat;
            $clock_in_lng = $objRow->clock_in_lng;
            $objRow->clock_in_loc = "";
            if (isset($clock_in_lat) && isset($clock_in_lng)) {
                $objRow->clock_in_loc = $this->getLoc($clock_in_lat, $clock_in_lng)->display_name;
            }

            $clock_out_lat = $objRow->clock_out_lat;
            $clock_out_lng = $objRow->clock_out_lng;
            $objRow->clock_out_loc = "";
            if (isset($clock_out_lat) && isset($clock_out_lng) && $clock_out_lng != null) {
                $locAddress = $this->getLoc($clock_out_lat, $clock_out_lng);
                $objRow->clock_out_loc = isset($locAddress->display_name) ? $locAddress->display_name : "-";
            }


            $presence->clock_in_loc = $objRow->clock_in_loc;
            $presence->clock_out_loc = $objRow->clock_out_loc;
            $presence->save();
        }
        return response()->json(['status'=>'success','message'=>'success update!','code'=>200], 200);
    }
}