<?php

namespace App\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use App\Models\Employee;
use App\Models\Ticket;
use App\Models\TicketLog;
use App\Models\User;
use App\Notifications\TicketAssignedNotification;
use App\Notifications\TicketCreatedNotification;
use App\Notifications\TicketReplyNotification;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class TicketController extends Controller
{
    public function __construct()
    {
        $this->middleware('permission:tickets.view')->only(['index', 'store', 'show', 'storeMessage', 'updateStatus', 'updateAssignedTo']);
    }

    public function index(Request $request)
    {
        $allowedStatuses = ['new', 'in_progress', 'waiting', 'completed', 'rejected'];
        $allowedPriorities = ['high', 'medium', 'low'];

        $scope = trim((string) $request->query('scope', ''));
        $status = trim((string) $request->query('status', ''));
        $priority = trim((string) $request->query('priority', ''));

        $query = Ticket::query()
            ->with(['assignedTo.employee'])
            ->orderByDesc('id');

        if ($scope === 'assigned') {
            $query->where('assigned_to', Auth::id());
        } elseif ($scope === 'overdue') {
            $query->whereNotNull('due_at')
                ->where('due_at', '<', now())
                ->whereNotIn('status', ['completed', 'rejected']);
        }

        if ($status !== '' && in_array($status, $allowedStatuses, true)) {
            $query->where('status', $status);
        }

        if ($priority !== '' && in_array($priority, $allowedPriorities, true)) {
            $query->where('priority', $priority);
        }

        $tickets = $query->get();

        $employees = Employee::query()
            ->with('user')
            ->orderBy('full_name')
            ->get();

        $allTicketsCount = Ticket::query()->count();
        $assignedToMeCount = Ticket::query()->where('assigned_to', Auth::id())->count();
        $overdueCount = Ticket::query()
            ->whereNotNull('due_at')
            ->where('due_at', '<', now())
            ->whereNotIn('status', ['completed', 'rejected'])
            ->count();

        return view('pages.tickets', [
            'tickets' => $tickets,
            'employees' => $employees,
            'scope' => $scope,
            'status' => $status,
            'priority' => $priority,
            'allTicketsCount' => $allTicketsCount,
            'assignedToMeCount' => $assignedToMeCount,
            'overdueCount' => $overdueCount,
        ]);
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'title' => ['required', 'string', 'max:255'],
            'description' => ['required', 'string'],
            'type' => ['required', 'string', 'max:255'],
            'priority' => ['required', 'in:high,medium,low'],
            'due_at' => ['nullable', 'date'],
            'assigned_to' => ['nullable', 'integer', 'exists:users,id'],
        ]);

        $ticket = Ticket::query()->create([
            'ticket_number' => Ticket::generateTicketNumber(),
            'title' => $validated['title'],
            'description' => $validated['description'],
            'type' => $validated['type'],
            'priority' => $validated['priority'],
            'status' => 'new',
            'created_by' => Auth::id(),
            'assigned_to' => $validated['assigned_to'] ?? null,
            'due_at' => $validated['due_at'] ?? null,
        ]);

        TicketLog::query()->create([
            'ticket_id' => $ticket->id,
            'user_id' => Auth::id(),
            'action' => 'ticket_created',
        ]);

        $creator = User::query()->find(Auth::id());
        $creator?->notify(new TicketCreatedNotification($ticket));

        if ($ticket->assigned_to && $ticket->assigned_to !== Auth::id()) {
            $assignee = User::query()->find($ticket->assigned_to);
            if ($assignee) {
                $assignee->notify(new TicketCreatedNotification($ticket));
            }
        }

        return redirect()
            ->route('tickets')
            ->with('success', __('tickets.created_successfully'));
    }

    public function show(int $id)
    {
        $ticket = Ticket::query()
            ->with(['assignedTo.employee', 'messages.user', 'logs.user'])
            ->findOrFail($id);

        $employees = Employee::query()
            ->with('user')
            ->orderBy('full_name')
            ->get();

        return view('pages.ticket_show', compact('ticket', 'employees'));
    }

    public function storeMessage(Request $request, int $id)
    {
        $validated = $request->validate([
            'message' => ['required', 'string'],
        ]);

        $ticket = Ticket::query()->findOrFail($id);

        $ticket->messages()->create([
            'user_id' => Auth::id(),
            'message' => $validated['message'],
        ]);

        TicketLog::query()->create([
            'ticket_id' => $ticket->id,
            'user_id' => Auth::id(),
            'action' => 'comment_added',
        ]);

        $notifiedUserIds = [];
        $senderId = Auth::id();

        if ($ticket->created_by && $ticket->created_by !== $senderId) {
            $creatorUser = User::query()->find($ticket->created_by);
            $creatorUser?->notify(new TicketReplyNotification($ticket));
            $notifiedUserIds[] = $ticket->created_by;
        }

        if ($ticket->assigned_to && $ticket->assigned_to !== $senderId && ! in_array($ticket->assigned_to, $notifiedUserIds, true)) {
            $assigneeUser = User::query()->find($ticket->assigned_to);
            $assigneeUser?->notify(new TicketReplyNotification($ticket));
        }

        return redirect()
            ->route('tickets.show', $ticket->id)
            ->with('success', __('tickets.messages.sent_successfully'));
    }

    public function updateStatus(Request $request, int $id)
    {
        $validated = $request->validate([
            'status' => ['required', 'in:new,in_progress,waiting,completed,rejected'],
        ]);

        $ticket = Ticket::query()->findOrFail($id);
        $ticket->update([
            'status' => $validated['status'],
        ]);

        TicketLog::query()->create([
            'ticket_id' => $ticket->id,
            'user_id' => Auth::id(),
            'action' => 'status_changed',
        ]);

        return redirect()
            ->route('tickets.show', $ticket->id)
            ->with('success', __('common.saved_successfully'));
    }

    public function updateAssignedTo(Request $request, int $id)
    {
        $validated = $request->validate([
            'assigned_to' => ['nullable', 'integer', 'exists:users,id'],
        ]);

        $ticket = Ticket::query()->findOrFail($id);
        $oldAssignedTo = $ticket->assigned_to;
        $ticket->update([
            'assigned_to' => $validated['assigned_to'] ?? null,
        ]);

        TicketLog::query()->create([
            'ticket_id' => $ticket->id,
            'user_id' => Auth::id(),
            'action' => 'assigned_changed',
        ]);

        $newAssignedTo = $ticket->assigned_to;
        if ($newAssignedTo && $newAssignedTo !== $oldAssignedTo) {
            $assignee = User::query()->find($newAssignedTo);
            if ($assignee) {
                $assignee->notify(new TicketAssignedNotification($ticket));
            }
        }

        return redirect()
            ->route('tickets.show', $ticket->id)
            ->with('success', __('common.saved_successfully'));
    }
}
