<?php

namespace App\Modules\Bookings;

use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\BaseController;
use App\Modules\Bookings\Comment;
use App\Modules\Bookings\Task;
use App\Modules\Bookings\Repair;
use App\Modules\Bookings\Project;
use App\Models\StatusChange;
use App\Models\AssignedChange;
use App\Models\User;
use Venturecraft\Revisionable\Revision;

class CommentControllerRESTv1 extends BaseController
{
    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index()
    {
        $query = Comment::select('comments.*')->with('creator');

        if (request()->has('task_type') || request()->has('assigned_to') || request()->has('completed') || request()->has('open')) {
            $query->join('tasks', 'tasks.id', '=', 'comments.related_id')->where('comments.related_type', '=', request()->get('type', 'task'));

            if (!request()->get('excludeUser')) {
                $query->where('tasks.assigned_to', '=', Auth::user()->id);
            }
        }

        if (request()->get('type') && request()->get('id')) {
            if (request()->get('type') != 'project') {
                $query = $query->where('related_type', '=', request()->get('type'))->where('related_id', '=', request()->get('id'));
            } else if (request()->get('type') == 'project') {
                // For projects we need to get all comments for all tasks in the project
                $query = $query->where('related_type', '=', request()->get('type'))->where('related_id', '=', request()->get('id'));
            }
        }

        if (request()->get('type') == 'project') {
            $linkedTaskIds = Task::where('project_id', '=', request()->get('id'))->pluck('id')->toArray(); //whereIn clause wants an array not a collection
            $query->orWhere(function ($q) use ($linkedTaskIds) {
                $q->where('related_type', '=', 'task')->whereIn('related_id', $linkedTaskIds);
            });
        }

        if (request()->get('task_type')) {
            $query->where('tasks.type', '=', request()->get('task_type'));
        }

        if (request()->get('assigned_to')) {
            $query->where('tasks.assigned_to', '=', request()->get('assigned_to'));
        }

        if (request()->get('completed') && request()->get('completed') != 'false') {
            $query->where('tasks.completed', '=', 1);
        }

        if (request()->get('open') && request()->get('open') != 'false') {
            $query->where('tasks.completed', '=', 0);
        }

        if (request()->has('public') && request()->get('public') != 'false') {
            $query->where('comments.public', '=', 1);
        }

        if (request()->get('modifiedSince')) {
            $query->where('comments.updated_at', '>=', request()->get('modifiedSince'));
        }

        // Get all comments without pagination first
        $comments = $query->get()->toArray();

        // Load related comment creators
        $commentIds = array_column($comments, 'id');
        if (!empty($commentIds)) {
            $creators = User::whereIn('id', array_unique(array_column($comments, 'created_by')))->get()->keyBy('id');
            foreach ($comments as &$comment) {
                if (isset($creators[$comment['created_by']])) {
                    $comment['creator'] = $creators[$comment['created_by']]->toArray();
                }
            }
        }

        switch (request()->get('type')) {
            case 'task':
                $task = DB::table('tasks')->where('id', request()->get('id'))->first();
                // We only update if the person who reads the comment is the person who has the job
                // assigned to him
                if ($task && Auth::check() && $task->assigned_to == Auth::user()->id) {
                    Comment::where('related_type', '=', request()->get('type'))->where('related_id', '=', request()->get('id'))->where('read', '=', 0)->update(['read' => 1]);
                }

                // Grab prebook changes
                if ($task) {
                    $prebooks = DB::table('revisions')
                        ->select('revisions.*', 'users.first_name', 'users.last_name', 'users.email')
                        ->join('users', 'users.id', '=', 'revisions.user_id')
                        ->where('revisionable_id', request()->get('id'))
                        ->where('revisionable_type', 'App\\Modules\\Bookings\\Task')
                        ->where('key', 'prebook')
                        ->get()
                        ->map(function ($item) {
                            return (array) $item;
                        })
                        ->toArray();
                }
                break;
        }

        // Mark comments as read for non-task types
        if (request()->get('type') !== 'task') {
            Comment::where('related_type', '=', request()->get('type'))->where('related_id', '=', request()->get('id'))->where('read', '=', 0)->update(['read' => 1]);
        }

        $statuses = StatusChange::where('related_type', '=', request()->get('type'))->where('related_id', '=', request()->get('id'))->with('new_status', 'old_status', 'user')->get()->toArray();
        $assigned = AssignedChange::where('related_type', '=', request()->get('type'))->where('related_id', '=', request()->get('id'))->with('new_user', 'old_user', 'user')->get()->toArray();

        // Only include field changes for users in Managers, Supervisors, or Developers groups
        $fieldChanges = [];
        if (Auth::check()) {
            $user = Auth::user();
            // Group IDs: 4=Managers, 14=Supervisors, 15=Developers
            if ($user->isMemberOf(4) || $user->isMemberOf(14) || $user->isMemberOf(15)) {
                $fieldChanges = \App\Models\FieldChange::where('related_type', '=', request()->get('type'))->where('related_id', '=', request()->get('id'))->with('user')->get()->toArray();
            }
        }

        if (!isset($prebooks)) {
            $prebooks = [];
        }

        // Merge all activity types and sort by created_at descending (newest first)
        $mergedData = array_merge($statuses, $comments, $assigned, $fieldChanges, $prebooks);
        usort($mergedData, function($a, $b) {
            return strtotime($b['created_at']) - strtotime($a['created_at']);
        });

        // Paginate the merged and sorted data
        $perPage = request()->get('limit', 20);
        $currentPage = request()->get('page', 1);
        $total = count($mergedData);
        $lastPage = ceil($total / $perPage);

        // Slice the data for current page
        $offset = ($currentPage - 1) * $perPage;
        $paginatedData = array_slice($mergedData, $offset, $perPage);

        $response = [
            'success'      => true,
            'data'         => $paginatedData,
            'total'        => $total,
            'current_page' => (int)$currentPage,
            'last_page'    => $lastPage,
        ];

        if (request()->get('type') == 'project') {
            $response['project'] = Project::with('client')->find(request()->get('id'))->toArray();
        }

        return Response::json($response);
    }

    /**
     * Store a newly created resource in storage.
     *
     * @return Response
     */
    public function store()
    {
        $data = request()->all();

        if (!request()->has('created_by')) {
            $data['created_by'] = Auth::user()->id;
        }

        $comment = Comment::create($data);

        if (! $comment->id) {
            return Response::json(['errors' => $comment->errors->all()], 400);
        }

        $comment->load('creator');

        return $comment;
    }

    /**
     * Store a newly created comment authed using pin/job in storage.
     *
     * @return Response
     */
    public function postCommentUsingPin($id, $pin, $comment)
    {

        $repair = Repair::find($id);
        //Check if the pin matches.  Otherwise throw error.
        if ($repair->pin == $pin) {

            $data = request()->all();

            $data['related_id'] = $id;
            $data['message'] = $comment;
            $data['created_by'] = 1;
            $data['related_type'] = 'task';
            $data['public'] = 1;

            $task = DB::table('tasks')->where('id', $data['related_id'])->first();

            $comment = Comment::create($data);

            if (!$comment->id) {
                return Response::json([
                    'errors' => $comment->errors->all(),
                ], 400);
            } else {
                $comment->load('creator');

                return Response::json($comment->toArray());
            }
        } else {
            return Response::json(['success' => false, 'errors' => ['Incorrect Pin!']], 400);
        }
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     *
     * @return Response
     */
    public function show($id)
    {
        $comment = Comment::find($id);

        if (! $comment) {
            return Response::json(['error' => 'Comment not found.'], 404);
        }

        $comment->load('creator');

        return Response::json($comment->toArray());
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  int  $id
     *
     * @return Response
     */
    public function update($id)
    {
        $comment = Comment::find($id);

        if (! $comment) {
            return Response::json(['error' => 'Comment not found.'], 404);
        }

        $comment->fill(request()->except('id'));

        if ($comment->save()) {
            $comment->load('creator');

            return Response::json($comment->toArray());
        } else {
            return Response::json(['errors' => $comment->errors->all()], 400);
        }
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     *
     * @return Response
     */
    public function destroy($id)
    {
        // Check if user has permission to delete comments (Managers, Supervisors, Developers only)
        if (!Auth::check()) {
            return Response::json(['error' => 'Unauthorized'], 401);
        }

        $user = Auth::user();
        // Group IDs: 4=Managers, 14=Supervisors, 15=Developers
        if (!($user->isMemberOf(4) || $user->isMemberOf(14) || $user->isMemberOf(15))) {
            return Response::json(['error' => 'You do not have permission to delete comments'], 403);
        }

        $comment = Comment::find($id);

        if (! $comment) {
            return Response::json(['error' => 'Comment not found.'], 404);
        }

        if ($comment->delete()) {
            return Response::json($comment->toArray());
        } else {
            return Response::json(['errors' => $comment->errors->all()], 400);
        }
    }
}
