<?php

namespace App\Http\Controllers\API\v1;

use App\Http\Controllers\Controller;
use App\Models\Mrf;
use App\Models\NotificationErrorLog;
use App\Models\User;
use App\Notifications\Mrf as MrfNotification;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;
use Exception;
use Throwable;

class MrfController extends Controller
{
    public function index(Request $request)
    {
        $employee = Auth::user();
        
        $keyword = $request->input('keyword', '');
        $perPage = $request->input('per_page', PHP_INT_MAX);
        $sortBy = $request->input('sortBy', '');
        $sortType = $request->input('sortType', '');


        $data = Mrf::with([
            'company',
            'jobtitle',
            'employmenttype',
            'requestor',
            'recommendor',
            'endorser',
            'approver',
            'employee'
        ])->where(function ($query) use ($keyword) {
            $query->whereHas('jobtitle', function ($q) use ($keyword) {
                $q->where('name', 'like', "%$keyword%");
            })
            ->orWhereHas('company', function ($q) use ($keyword) {
                $q->where('name', 'like', "%$keyword%");
            })
            ->orWhereHas('employmenttype', function ($q) use ($keyword) {
                $q->where('name', 'like', "%$keyword%");
            })
            ->orWhereHas('requestor', function ($q) use ($keyword) {
                $q->where('firstname', 'like', "%$keyword%")
                    ->orWhere('lastname', 'like', "%$keyword%");
            });
        });
             
        
        try{
            switch ($employee->employees->classification_id) {
                case 2:
                    $data->where('requested_by', $employee->employee_id);
                    break;
                case 3:
                    if ($employee->employees->position_id == 540 || $employee->employees->position_id == 21 || $employee->employees->position_id == 929) {
                        $data->where('endorsed_by', $employee->employee_id)
                            ->where('status', '>=', 1)
                            ->orWhere('requested_by', $employee->employee_id);
                    } else {
                        $data->where('recommended_by', $employee->employee_id)
                            ->orWhere('requested_by', $employee->employee_id);
                    }
                    break;
                case 4:
                    $data->where('approved_by', $employee->employee_id)
                        ->where('status', '>=', 2)
                        ->orWhere('requested_by', $employee->employee_id);
                    break;
            }
        } catch(Throwable $e) {

        }

        if (!empty($sortBy) && !empty($sortType)) {
            $data->orderBy($sortBy, $sortType);
        }

        $data->where('enabled', 1);

        $data = $data->paginate($perPage);
        
        return response()->json($data);
    }

    public function showApprovedMrf(Request $request)
    {
        $employee = Auth::user();
        
        $keyword = $request->input('keyword', '');
        $perPage = $request->input('per_page', PHP_INT_MAX);
        $sortBy = $request->input('sortBy', '');
        $sortType = $request->input('sortType', '');


        $data = Mrf::with([
            'company', 
            'jobtitle', 
            'employmenttype', 
            'requestor',
            'recommendor',
            'endorser',
            'approver',
            'employee'
        ])->where(function ($query) use ($keyword) {
            $keyword = str_replace(" ", "%", $keyword);
        });
        
        
        try{
            switch ($employee->employees->classification_id) {
                case 2:
                    $data->where('requested_by', $employee->employee_id);
                    break;
                case 3:
                    if ($employee->employees->position_id == 540 || $employee->employees->position_id == 21) {
                        $data->where('endorsed_by', $employee->employee_id)
                            ->where('status', '>=', 1)
                            ->orWhere('requested_by', $employee->employee_id);
                    } else {
                        $data->where('recommended_by', $employee->employee_id)
                            ->orWhere('requested_by', $employee->employee_id);
                    }
                    break;
                case 4:
                    $data->where('approved_by', $employee->employee_id)
                        ->where('status', '>=', 2)
                        ->orWhere('requested_by', $employee->employee_id);
                    break;
            }
        } catch(Throwable $e) {

        }

        if (!empty($sortBy) && !empty($sortType)) {
            $data->orderBy($sortBy, $sortType);
        }

        $data->where('enabled', 1)->where('status', 3);

        $data = $data->paginate($perPage);

        // dd($data);
        
        return response()->json($data);
    }

    public function showOpenPositionMrf(Request $request)
    {
        $data = Mrf::with('jobtitle:id,name')->select('job_title')->distinct()->get();
        
        return response()->json($data);
    }

    public function showMrfWithApplicants()
    {
        $mrfs = Mrf::with([
            'applicants' => function($query) {
                $query->where('applicants.status', 0);
                $query->where('applicants.blocklist', 0);
            }, 
            'company', 
            'jobtitle'
        ])->get();

        if ($mrfs->isEmpty()) {
            return response()->json([
                'message' => 'No Mrf records found.'
            ], 404);
        }

        $response = $mrfs->map(function($mrf) {
            return [
                'mrf' => $mrf,
                'applicant_count' => $mrf->applicants->count(),
                'applicants' => $mrf->applicants
            ];
        });

        return response()->json($response);
    }

    public function showArchiveApplicants(Request $request)
    {
        // dd($request->all());
        $keyword = $request->input('keyword', '');
        $perPage = $request->input('per_page', PHP_INT_MAX);
        $sortBy = $request->input('sortBy', '');
        $sortType = $request->input('sortType', '');

        $mrfs = Mrf::with([
            'applicants' => function ($query) {
                $query->onlyTrashed(); // Get only soft-deleted applicants
            },
            'company',
            'jobtitle',
        ])
        ->where(function ($query) use ($keyword) {
            $query->whereHas('jobtitle', function ($q) use ($keyword) {
                $q->where('name', 'like', "%$keyword%");
            })
            ->orWhereHas('company', function ($q) use ($keyword) {
                $q->where('name', 'like', "%$keyword%");
            });
        })
        ->whereHas('applicants', function ($query) use ($keyword) {
            // Ensure soft-deleted applicants and apply the keyword filter
            $query->onlyTrashed();
        })
        ->get();
        
        // if ($mrfs->isEmpty()) {
        //     $mrfs = [];
        //     // return response()->json([
        //     //     'message' => 'No Mrf records with trashed applicants found.'
        //     // ], 404);
        // }
        
        $response = $mrfs->map(function ($mrf) {
            return [
                'mrf' => $mrf,
                'trashed_applicant_count' => $mrf->applicants->count(),
                'trashed_applicants' => $mrf->applicants
            ];
        });
        
        return response()->json($response);
    }

    public function showBlocklistApplicants(Request $request)
    {
        $keyword = $request->input('keyword', '');
        $perPage = $request->input('per_page', PHP_INT_MAX);
        $sortBy = $request->input('sortBy', '');
        $sortType = $request->input('sortType', '');

        $mrfs = Mrf::with([
            'applicants' => function ($query) {
                $query->where('blocklist', 1);
            },
            'company',
            'jobtitle'
        ])
        ->where(function ($query) use ($keyword) {
            $query->whereHas('jobtitle', function ($q) use ($keyword) {
                $q->where('name', 'like', "%$keyword%");
            })
            ->orWhereHas('company', function ($q) use ($keyword) {
                $q->where('name', 'like', "%$keyword%");
            });
        })
        ->whereHas('applicants', function ($query) {
            $query->where('blocklist', 1);
        })->get();
        
        $response = $mrfs->map(function ($mrf) {
            return [
                'mrf' => $mrf,
                'trashed_applicant_count' => $mrf->applicants->count(),
                'trashed_applicants' => $mrf->applicants
            ];
        });
        
        return response()->json($response);
    }

    public function show($id)
    {
        $data = Mrf::with(['company', 'jobtitle', 'employmenttype'])->find($id);

        if (!$data) {
            return response()->json(['message' => 'Record not found'], 404);
        }

        return response()->json($data);
    }

    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'company_id' => "required",
        ]);

        if ($validator->fails()) {
            return $this->validationErrorResponse($validator);
        }

        DB::beginTransaction();
        try {
            $attachment_name = $this->handleFileUpload($request->file('supporting_document'), 'mrf');
            $status = Mrf::create($this->prepareMrfData($request, $attachment_name));
            DB::commit();

            $status->load(['employee']);

            $this->sendNotification($request, $status);
            
            // dd();

            return response()->json([
                'status'  => true,
                'message' => 'Saved successfully!',
                'data'    => $status
            ], 201);

        } catch (Exception $e) {
            DB::rollBack();
            return $this->exceptionResponse($e);
        }
    }

    public function update(Request $request)
    {
        $data = Mrf::find($request->id);

        if($request->status == 99){
            $now = date('Y-m-d H:i:s');

            $request['status'] = 0;
            $request['denied_at'] = $now;
        }

        if (!$data) {
            return response()->json(['message' => 'Record not found'], 404);
        }

        $validator = Validator::make($request->all(), [
            'company_id' => "required",
        ]);
        
        if ($validator->fails()) {
            return $this->validationErrorResponse($validator);
        }

        DB::beginTransaction();
        try {
            $attachment_name = $request->supporting_document;
            
            if ($data->supporting_document != $request->supporting_document) {
                $this->deleteFile('mrf/' . $data->supporting_document);
                $attachment_name = $this->handleFileUpload($request->file('supporting_document'), 'mrf');
            }

            $data->fill($this->prepareMrfData($request, $attachment_name));
            $data->save();
            DB::commit();

            return response()->json([
                'status'  => true,
                'message' => 'Updated successfully!',
                'data'    => $data
            ], 201);

        } catch (Exception $e) {
            DB::rollBack();
            return $this->exceptionResponse($e);
        }
    }

    public function updateStatus(Request $request, $id)
    {
        // dd($request->all());

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

        if (!$data) {
            return response()->json(['message' => 'No data found.'], 404);
        }

        DB::beginTransaction();
        try {
            $now = date('Y-m-d H:i:s');

            switch ($request->status) {
                case 3:
                    $request['approved_at'] = $now;
                    break;
                case 1:
                    $request['recommended_at'] = $now;
                    break;
                case 2:
                    $request['endorsed_at'] = $now;
                    break;
            }
            

            $request->status == 3 ? $request['approved_at'] = date('Y-m-d') : '';

            $data->fill($request->all());
            $data->save();
            DB::commit();

            $employee_id_for_notification = $this->getEmployeeIdForNotification($request->status, $data);
            $this->sendNotificationToEmployee($employee_id_for_notification, $data);

            return response()->json([
                'message' => 'Record successfully updated!',
                'status' => 'success',
                'data' => $data,
            ], 201);

        } catch (Exception $e) {
            DB::rollBack();
            return $this->exceptionResponse($e);
        }
    }

    public function closeMrf(Request $request, $id)
    {
        // dd($request->all());

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

        if (!$data) {
            return response()->json(['message' => 'No data found.'], 404);
        }

        DB::beginTransaction();
        try {
            $now = date('Y-m-d');

            $request['closed_at'] = $now;
            $request['enabled'] = 0;

            $data->fill($request->all());
            $data->save();
            DB::commit();

            return response()->json([
                'message' => 'Record successfully updated!',
                'status' => 'success',
                'data' => $data,
            ], 201);

        } catch (Exception $e) {
            DB::rollBack();
            return $this->exceptionResponse($e);
        }
    }

    public function destroy($id)
    {
        $data = Mrf::find($id);

        if (!$data) {
            return response()->json(['message' => "Record not found!"], 204);
        }

        DB::beginTransaction();
        try {
            $data->delete();
            DB::commit();
            return response()->json(['message' => "Record successfully deleted!"], 201);
        } catch (Exception $e) {
            DB::rollBack();
            return $this->exceptionResponse($e);
        }
    }

    private function handleFileUpload($file, $path)
    {
        if ($file) {
            $attachment_name = time() . '_' . $file->getClientOriginalName();
            $storagePath = "$path/$attachment_name";
            Storage::disk('local')->put($storagePath, file_get_contents($file));
            return $attachment_name;
        }
        return '';
    }

    private function deleteFile($path)
    {
        if (Storage::exists($path)) {
            Storage::delete($path);
        }
    }

    private function prepareMrfData($request, $attachment_name)
    {
        return [
            'company_id' => $request->company_id,
            'nature_of_request' => $request->nature_of_request,
            'classification' => $request->classification,
            'job_title' => $request->job_title,
            'salary_grade' => $request->salary_grade,
            'salary' => $request->salary,
            'replacement_position_number' => $request->replacement_position_number,
            'employee_name_to_be_replaced1' => $request->employee_name_to_be_replaced1,
            'nature_of_seperation1' => $request->nature_of_seperation1,
            'date_of_seperation1' => $request->date_of_seperation1,
            'new_position_number' => $request->new_position_number,
            'date_needed' => $request->date_needed,
            'employment_status' => $request->employment_status,
            'supporting_document' => $attachment_name,
            'document_type' => $request->document_type,
            'working_position_title' => $request->working_position_title,
            'inclusive_period' => $request->inclusive_period,
            'justification' => $request->justification,
            'job_design' => $request->job_design,
            'requested_by' => $request->requested_by,
            'recommended_by' => $request->recommended_by,
            'endorsed_by' => $request->endorsed_by,
            'approved_by' => $request->approved_by,
            'status' => $request->status
        ];
    }

    private function sendNotification($request, $status)
    {
        $email_to = match ($request->status) {
            2 => $this->getEmployeeEmailData($request->approved_by),
            1 => $this->getEmployeeEmailData($request->endorsed_by),
            default => $this->getEmployeeEmailData($request->recommended_by),
        };

        if ($email_to) {
            Notification::send($email_to, new MrfNotification($status));
        }
    }

    private function getEmployeeIdForNotification($status, $data)
    {
        return match ($status) {
            3 => $data->requested_by,
            2 => $data->approved_by,
            1 => $data->endorsed_by,
            default => $data->recommended_by,
        };
    }

    private function sendNotificationToEmployee($employee_id, $status)
    {
        $email_to = $this->getEmployeeEmailData($employee_id);
        if ($email_to) {
            Notification::send($email_to, new MrfNotification($status));
        }
    }

    private function getEmployeeEmailData($employee_id)
    {
        return User::whereHas('employees', function ($query) use ($employee_id) {
            $query->where('employee_id', $employee_id);
        })->get();
    }

    private function validationErrorResponse($validator)
    {
        return response()->json([
            'status' => false,
            'message' => 'Validation failed!',
            'error' => $validator->errors()
        ], 422);
    }

    private function exceptionResponse($exception)
    {
        return response()->json([
            'status' => false,
            'message' => 'An error occurred!',
            'error' => $exception->getMessage()
        ], 500);
    }

    public function removeAttachment(Request $request)
    {
        $id = $request->id;
        $attachment = $request->supporting_document;

        $data = Mrf::where('id', $id)->first();

        $data->attachment = NULL;

        $data->save();

        DB::connection()->commit();

        $attachment_file_path = 'mrf/' . $request->supporting_document;
        if(Storage::exists($attachment_file_path))
        {
            Storage::delete($attachment_file_path);
        }

        return response()->json([
            'status'  => true,
            'message' => 'Saved successfully!',
            'data'    => $data
        ],201);
    }
}
