<?php

namespace App\Http\Controllers\api;

use App\Models\Job;
use App\Models\Profile;
use App\Models\JobSkill;
use App\Models\Applicant;
use App\Models\UserSkill;
use Illuminate\Support\Str;
use App\Models\JobParameter;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use App\Http\Resources\JobResource;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Validator;

class JobController extends Controller
{
    public function index(Request $request)
    {
        $jobs = Job::select("*")->whereRaw('recruit_id IS NULL');

        $search = isset($request->search) ? $request->search : '';
        if (!empty($search)) {
            $jobs->where(function ($query) use ($search) {
                $query->where('name', 'like', '%'.$search.'%');
            });
        }

        // $length = intval(isset($request->length) ? $request->length : 10);
        // $start = intval(isset($request->start) ? $request->start : 0);

        // $jobs = $jobs->skip($start)->take($length)->get();

        $jobs = $jobs->get();

        return response()->json([
            'error' => false,
            'message' => 'Berhasil mengambil data.',
            'data' => JobResource::collection($jobs->loadMissing(['skills', 'parameters', 'applicants']))
        ], 200);
    }

    public function index2(Request $request)
    {
        $jobs = Job::select("*");

        $search = isset($request->search['value']) ? $request->search['value'] : '';
        if (!empty($search)) {
            $jobs->where(function ($query) use ($search) {
                $query->where('name', 'like', '%'.$search.'%');
            });
        }

        $total_data = $jobs->count();
        $length = intval(isset($request->length) ? $request->length : 0);
        $start = intval(isset($request->start) ? $request->start : 0);

        if (!isset($request->length) || !isset($request->start)) {
            $jobs = $jobs->get();
        } else {
            $jobs = $jobs->skip($start)->take($length)->get();
        }

        return response()->json([
            'error' => false,
            'message' => 'Berhasil mengambil data.',
            'data' => JobResource::collection($jobs->loadMissing(['skills', 'parameters', 'applicants'])),
            'draw' => $request->draw,
            'recordsTotal' => $total_data,
            'recordsFiltered' => $total_data,
        ], 200);
    }

    public function show_applied_job(Request $request, $user_id)
    {
        $jobs = Job::select(["*","jobs.id", "jobs.user_id"])->join('applicants', 'applicants.job_id', 'jobs.id')
        ->where('applicants.user_id', $user_id);

        $search = isset($request->search) ? $request->search : '';
        if (!empty($search)) {
            $jobs->where(function ($query) use ($search) {
                $query->where('name', 'like', '%'.$search.'%');
            });
        }

        // $length = intval(isset($request->length) ? $request->length : 10);
        // $start = intval(isset($request->start) ? $request->start : 0);

        // $jobs = $jobs->skip($start)->take($length)->get();

        $jobs = $jobs->get();

        return response()->json([
            'error' => false,
            'message' => 'Berhasil mengambil data.',
            'data' => JobResource::collection($jobs->loadMissing(['skills', 'parameters', 'applicants']))
        ], 200);
    }

    public function owner_jobs(Request $request, $user_id)
    {
        $jobs = Job::where('user_id', $user_id);

        $search = isset($request->search) ? $request->search : '';
        if (!empty($search)) {
            $jobs->where(function ($query) use ($search) {
                $query->where('name', 'like', '%'.$search.'%');
            });
        }

        // $length = intval(isset($request->length) ? $request->length : 10);
        // $start = intval(isset($request->start) ? $request->start : 0);

        // $jobs = $jobs->skip($start)->take($length)->get();

        $jobs = $jobs->get();

        return response()->json([
            'error' => false,
            'message' => 'Berhasil mengambil data.',
            'data' => JobResource::collection($jobs->loadMissing(['skills', 'parameters']))
        ], 200);
    }

    public function show($id)
    {
        $job = Job::where('id', $id)->get();
        return response()->json([
            'error' => false,
            'message' => 'Berhasil mengambil data.',
            'data' => JobResource::collection($job->loadMissing(['skills', 'parameters']))
        ], 200);
    }

    public function store(Request $request)
    {
        ini_set('max_execution_time', 600);
        $validator = Validator::make($request->all(), [
            'user_id' => 'required',
            'name' => 'required',
            'description' => 'required',
            'accommodation' => 'required',
            'working_days' => 'required',
            'working_hours' => 'required',
            'image' => 'required|file|mimes:jpg,png,jpeg|max:5048',
            'salary' => 'required',
            'address' => 'required',
            'location' => 'required',
            'recomended_age' => 'required',
        ], [
            'required' => ':attribute harus diisi.',
            'file' => ':attribute harus berupa file.',
            'mimes' => 'File :attribute harus berformat jpg, jpeg, atau png.',
            'max' => 'File :attribute tidak boleh lebih dari :max KB.',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'error' => true,
                'message' => Str::ucfirst($validator->errors()->first()),
                'data' => null
            ]);
        }

        // Upload File
        $namaimage = $this->generateRandomString(33).time();
        $ekstensiimage = $request->image->extension();

        $pathimage = '/assets/storage/document/job/image/' . $namaimage . "." . $ekstensiimage;
        $request->image->move(public_path('assets/storage/document/job/image'), $pathimage);
        // End Upload File

        $job = Job::create([
            'user_id' => $request->input('user_id'),
            'name' => $request->input('name'),
            'description' => $request->input('description'),
            'accommodation' => $request->input('accommodation'),
            'working_days' => $request->input('working_days'),
            'working_hours' => $request->input('working_hours'),
            'image' => $pathimage,
            'salary' => $request->input('salary'),
            'address' => $request->input('address'),
            'location' => $request->input('location'),
            'recomended_age' => $request->input('recomended_age'),
        ]);

        return response()->json([
            'error' => false,
            'message' => 'Job berhasil ditambahkan.',
            'id' => $job->id,
            'data' => null
        ]);
    }

    public function update(Request $request, $id)
    {
        ini_set('max_execution_time', 300);
        $validator = Validator::make($request->all(), [
            'name' => 'required',
            'description' => 'required',
            'accommodation' => 'required',
            'working_days' => 'required',
            'working_hours' => 'required',
            'image' => 'required',
            'salary' => 'required',
            'address' => 'required',
            'location' => 'required',
            'recomended_age' => 'required',
        ], [
            'required' => ':attribute harus diisi.',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'error' => true,
                'message' => Str::ucfirst($validator->errors()->first()),
                'data' => null
            ]);
        }

        $update = [
            'name' => $request->input('name'),
            'description' => $request->input('description'),
            'image' => $request->input('image'),
            'salary' => $request->input('salary'),
            'address' => $request->input('address'),
            'location' => $request->input('location'),
            'recomended_age' => $request->input('recomended_age'),
        ];

        $job = Job::findOrFail($id);
        $job->update($update);

        return response()->json([
            'error' => false,
            'message' => 'Job berhasil diubah.',
            'data' => null
        ]);
    }

    public function destroy($id)
    {
        $job = Job::findOrFail($id);

        $name = $job->name;

        $job->delete();

        return response()->json([
            'error' => false,
            'message' => 'Job '.$name.' berhasil dihapus.',
            'data' => null
        ]);
    }

    public function add_skills(Request $request, $id) {
        $validator = Validator::make($request->all(), [
            'skills' => 'required|array',
        ], [
            'required' => ':attribute harus diisi.',
            'array' => ':attribute harus berupa array.',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'error' => true,
                'message' => Str::ucfirst($validator->errors()->first()),
                'data' => null
            ]);
        }

        $job = Job::find($id);
        $skills = $request->input('skills');

        foreach ($skills as $skill) {
            if (!empty($skill)) {
                JobSkill::create(['skill_id' => $skill, 'job_id' => $id]);
            }
        }

        return response()->json([
            'error' => false,
            'message' => 'Berhasil menambahkan skill.',
            'data' => null
        ]);
    }

    public function add_parameter(Request $request, $id) {
        $validator = Validator::make($request->all(), [
            'parameters' => 'required|array',
        ], [
            'required' => ':attribute harus diisi.',
            'array' => ':attribute harus berupa array.',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'error' => true,
                'message' => Str::ucfirst($validator->errors()->first()),
                'data' => null
            ]);
        }

        $job = Job::find($id);
        $parameters = $request->input('parameters');

        $jobParameters = [];
        foreach ($parameters as $parameter) {
            JobParameter::create(['job_id' => $id, 'parameter_id' => $parameter['parameter_id'], 'weight' => $parameter['weight']]);
        }

        return response()->json([
            'error' => false,
            'message' => 'Berhasil menambahkan parameter.',
            'data' => null
        ]);
    }

    public function add_applicant(Request $request, $id)
    {
        $validator = Validator::make($request->all(), [
            'user_id' => 'required',
            // 'param_distance' => 'required',
        ], [
            'required' => ':attribute harus diisi.',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'error' => true,
                'message' => Str::ucfirst($validator->errors()->first()),
                'data' => null
            ]);
        }

        $job = Job::find($id);
        $user_id = $request->input('user_id');

        $profile = Profile::where('user_id', $user_id)->first();
        $userSkills = UserSkill::where('user_id', $user_id)->pluck('skill_id');
        $jobSkills = JobSkill::where('job_id', $id)->pluck('skill_id');

        $now = Carbon::now();
        $user_age = $now->diffInYears($profile->birthdate);
        $param_age = abs($user_age - $job->recomended_age);
        $param_salary = number_format($profile->desired_salary / $job->salary, 5, '.', '');
        $param_skill = $userSkills->intersect($jobSkills)->count();

        $userLocation = json_decode($profile->location, true);
        $jobLocation = json_decode($job->location, true);

        // Menghitung Garis Lurus
        $param_distance = $this->haversine($userLocation, $jobLocation);

        $formattedDistance = number_format($param_distance, 2);

        $applicant = Applicant::create([
            'user_id' => $user_id,
            'job_id' => $id,
            'param_age' => $param_age+1,
            'param_salary' => $param_salary,
            'param_skill' => $param_skill+1,
            'param_distance' => $formattedDistance+1,
        ]);

        return response()->json([
            'error' => false,
            'message' => 'Berhasil mendaftar di job ini.',
            'data' => $applicant
        ]);
    }

    public function recruit_applicant(Request $request, $id)
    {
        $validator = Validator::make($request->all(), [
            'recruit_id' => 'required',
        ], [
            'required' => ':attribute harus diisi.',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'error' => true,
                'message' => Str::ucfirst($validator->errors()->first()),
                'data' => null
            ]);
        }

        $update = [
            'recruit_id' => $request->input('recruit_id'),
        ];

        $job = Job::findOrFail($id);
        $job->update($update);

        return response()->json([
            'error' => false,
            'message' => 'Calon maid berhasil direkrut.',
            'data' => null
        ]);
    }

    public function show_applicant(Request $request, $id)
    {
        $job = Job::findOrFail($id);
        $applicants = Applicant::where('job_id', $id);

        $order_by = $request->query('order_by', 'id');
        $order_dir = $request->query('order_dir', 'asc');

        if ($order_by === 'param_distance') {
            $applicants = $applicants->orderBy('param_distance', $order_dir);
        } elseif ($order_by === 'param_skill') {
            $applicants = $applicants->orderBy('param_skill', $order_dir);
        } elseif ($order_by === 'umur') {
            $applicants = $applicants->orderBy(function ($applicant) {
                return \Carbon\Carbon::parse($applicant->user->birthdate)->age;
            }, $order_dir);
        } else {
            $applicants = $applicants->orderBy('id', $order_dir);
        }

        $applicants = $applicants->get();

        return response()->json([
            'error' => false,
            'message' => 'Berhasil mengambil data.',
            'data' => $applicants
        ], 200);
    }

    public function show_recent_applicant(Request $request, $user_id)
    {
        $applicants = Applicant::select(
            [
                'applicants.id',
                'applicants.job_id',
                'applicants.user_id',
                'users.name',
                'jobs.name as job_name',
                'jobs.recruit_id',
                'param_age',
                'param_salary',
                'param_skill',
                'param_distance',
            ]
        )
        ->join('users', 'users.id', '=', 'user_id')
        ->join('jobs', 'jobs.id', '=', 'job_id')
        ->where('jobs.user_id', $user_id);

        $order_by = $request->query('order_by', 'id');
        $order_dir = $request->query('order_dir', 'desc');

        $applicants = $applicants->orderBy($order_by, $order_dir)->get();

        $results = [];
        foreach ($applicants as $applicant) {
            $results[] = [
                'applicant' => $applicant,
                'score' => 0
            ];
        }

        return response()->json([
            'error' => false,
            'message' => 'Berhasil mengambil data.',
            'data' => $results
        ], 200);
    }

    public function show_applicant_wp(Request $request, $id)
    {
        $applicants = Applicant::select(
            [
                'applicants.id',
                'applicants.job_id',
                'applicants.user_id',
                'users.name',
                'jobs.name as job_name',
                'jobs.recruit_id',
                'param_age',
                'param_salary',
                'param_skill',
                'param_distance',
            ]
        )
        ->join('users', 'users.id', '=', 'user_id')
        ->join('jobs', 'jobs.id', '=', 'job_id')
        ->where('job_id', $id)->get();

        $umur_w = JobParameter::where('job_id', $id)->where('parameter_id', 1)->get()[0]->weight;
        $gaji_w = JobParameter::where('job_id', $id)->where('parameter_id', 2)->get()[0]->weight;
        $skill_w = JobParameter::where('job_id', $id)->where('parameter_id', 3)->get()[0]->weight;
        $lokasi_w = JobParameter::where('job_id', $id)->where('parameter_id', 4)->get()[0]->weight;

        $total_w = ($umur_w+$gaji_w+$skill_w+$lokasi_w);

        $umur_w = ($umur_w/$total_w)*-1; // Cost
        $gaji_w = ($gaji_w/$total_w)*-1; // Cost
        $skill_w = ($skill_w/$total_w)*1; // Benefit
        $lokasi_w = ($lokasi_w/$total_w)*-1; // Cost

        $total_score = 0;
        $results = [];
        foreach ($applicants as $applicant) {
            // Calculate weighted product score
            $score = pow($applicant->param_age, $umur_w) *
                     pow($applicant->param_salary, $gaji_w) *
                     pow($applicant->param_skill, $skill_w) *
                     pow($applicant->param_distance, $lokasi_w);

            $total_score += $score;

            $results[] = [
                'applicant' => $applicant,
                'score' => $score
            ];
        }

        // Calculate vector V (normalized scores)
        foreach ($results as &$result) {
            $result['score'] = $result['score'] / $total_score;
        }

        // Sort applicants by score descending
        usort($results, function($a, $b) {
            return $b['score'] <=> $a['score'];
        });

        return response()->json([
            'error' => false,
            'message' => 'Berhasil mengambil data.',
            'data' => $results
        ], 200);
    }

    function generateRandomString($length = 10) {
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $randomString = '';
        for ($i = 0; $i < $length; $i++) {
            $randomString .= $characters[rand(0, strlen($characters) - 1)];
        }
        return $randomString;
    }

    function haversine($userLocation, $jobLocation) {
        $earthRadius = 6371; // Jari-jari bumi dalam kilometer

        // Mengambil koordinat dari parameter
        $lat1 = $userLocation['lat'];
        $lon1 = $userLocation['lng'];
        $lat2 = $jobLocation['lat'];
        $lon2 = $jobLocation['lng'];

        // Menghitung perbedaan dalam radian
        $dLat = deg2rad($lat2 - $lat1);
        $dLon = deg2rad($lon2 - $lon1);

        // Menghitung komponen 'a' dalam rumus Haversine
        $a = sin($dLat / 2) * sin($dLat / 2) +
             cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
             sin($dLon / 2) * sin($dLon / 2);

        // Menghitung komponen 'c'
        $c = 2 * asin(sqrt($a));

        // Menghitung dan mengembalikan jarak
        return $earthRadius * $c;
    }
}


