<?php

declare(strict_types=1);

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\AuditLog;
use App\Models\CannedResponse;
use App\Models\Department;
use App\Models\SupportTicket;
use App\Models\TicketReply;
use App\Models\TicketTag;
use App\Models\User;
use App\Notifications\TicketStaffReplyNotification;
use App\Notifications\TicketStatusChangedNotification;
use App\Services\Support\SlaService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;

class TicketController extends Controller
{
    public function __construct(
        private readonly SlaService $slaService,
    ) {}

    public function index(Request $request): Response
    {
        $query = SupportTicket::query()
            ->with(['user:id,name,email', 'assignee:id,name', 'tags', 'departmentRelation:id,name']);

        if ($search = $request->input('search')) {
            $query->where(function ($q) use ($search): void {
                $q->where('subject', 'like', "%{$search}%")
                    ->orWhereHas('user', function ($uq) use ($search): void {
                        $uq->where('name', 'like', "%{$search}%")
                            ->orWhere('email', 'like', "%{$search}%");
                    });
            });
        }

        if ($status = $request->input('status')) {
            $query->where('status', $status);
        }

        if ($priority = $request->input('priority')) {
            $query->where('priority', $priority);
        }

        if ($department = $request->input('department')) {
            $query->where('department', $department);
        }

        if ($assignedTo = $request->input('assigned_to')) {
            $query->where('assigned_to', $assignedTo);
        }

        if ($tagIds = $request->input('tags')) {
            $tagArray = is_array($tagIds) ? $tagIds : explode(',', $tagIds);
            $query->whereHas('tags', function ($q) use ($tagArray): void {
                $q->whereIn('ticket_tags.id', $tagArray);
            });
        }

        if ($request->boolean('sla_breached')) {
            $query->where(function ($q): void {
                $q->where('sla_first_response_breached', true)
                    ->orWhere('sla_resolution_breached', true);
            });
        }

        $tickets = $query->latest('updated_at')
            ->paginate(25)
            ->withQueryString();

        $tags = TicketTag::query()->orderBy('name')->get();
        $staffUsers = User::role('admin')->select('id', 'name')->orderBy('name')->get();
        $departments = Department::query()->orderBy('sort_order')->get(['id', 'name', 'slug']);

        return Inertia::render('Admin/Tickets/Index', [
            'tickets' => $tickets,
            'tags' => $tags,
            'staffUsers' => $staffUsers,
            'departments' => $departments,
            'filters' => [
                'search' => $request->input('search', ''),
                'status' => $request->input('status', ''),
                'priority' => $request->input('priority', ''),
                'department' => $request->input('department', ''),
                'assigned_to' => $request->input('assigned_to', ''),
                'tags' => $request->input('tags', ''),
                'sla_breached' => $request->boolean('sla_breached'),
            ],
        ]);
    }

    public function show(SupportTicket $ticket): Response
    {
        $ticket->load([
            'replies.user:id,name,email',
            'user:id,name,email,status,company',
            'assignee:id,name,email',
            'tags',
            'departmentRelation:id,name,slug',
            'slaPolicy',
            'satisfactionRating',
        ]);

        $cannedResponses = CannedResponse::query()
            ->where('is_shared', true)
            ->orderBy('title')
            ->get(['id', 'title', 'content', 'category']);

        $tags = TicketTag::query()->orderBy('name')->get();

        $staffUsers = User::role('admin')->select('id', 'name', 'email')->orderBy('name')->get();

        $departments = Department::query()->orderBy('sort_order')->get(['id', 'name', 'slug']);

        return Inertia::render('Admin/Tickets/Show', [
            'ticket' => $ticket,
            'cannedResponses' => $cannedResponses,
            'tags' => $tags,
            'staffUsers' => $staffUsers,
            'departments' => $departments,
        ]);
    }

    public function reply(Request $request, SupportTicket $ticket): RedirectResponse
    {
        $validated = $request->validate([
            'body' => ['required', 'string', 'max:5000'],
            'status' => ['nullable', 'in:open,in_progress,waiting,closed'],
            'is_internal' => ['boolean'],
            'tags' => ['nullable', 'array'],
            'tags.*' => ['integer', 'exists:ticket_tags,id'],
        ]);

        $isInternal = $validated['is_internal'] ?? false;

        $reply = TicketReply::query()->create([
            'ticket_id' => $ticket->id,
            'user_id' => $request->user()->id,
            'body' => $validated['body'],
            'is_staff_reply' => true,
            'is_internal' => $isInternal,
        ]);

        $updateData = ['last_reply_at' => now()];

        if (! empty($validated['status'])) {
            $updateData['status'] = $validated['status'];

            if ($validated['status'] === 'closed') {
                $updateData['resolved_at'] = now();
            }
        }

        $ticket->update($updateData);

        // Record first response for SLA tracking (only for non-internal replies)
        if (! $isInternal) {
            $this->slaService->recordFirstResponse($ticket);
        }

        // Sync tags if provided
        if (isset($validated['tags'])) {
            $ticket->tags()->sync($validated['tags']);
        }

        // Only notify customer for non-internal replies
        if (! $isInternal) {
            $ticket->user?->notify(new TicketStaffReplyNotification($ticket, $reply));
        }

        // Track canned response usage if applicable
        if ($cannedResponseId = $request->input('canned_response_id')) {
            CannedResponse::query()
                ->where('id', $cannedResponseId)
                ->increment('usage_count');
        }

        AuditLog::query()->create([
            'user_id' => $ticket->user_id,
            'admin_id' => $request->user()->id,
            'action' => $isInternal ? 'internal_note_ticket' : 'reply_ticket',
            'resource_type' => 'support_ticket',
            'resource_id' => $ticket->id,
            'ip_address' => $request->ip(),
            'user_agent' => $request->userAgent(),
        ]);

        return redirect()->back()->with('success', $isInternal ? 'Internal note added.' : 'Reply sent successfully.');
    }

    public function updateStatus(Request $request, SupportTicket $ticket): RedirectResponse
    {
        $validated = $request->validate([
            'status' => ['required', 'in:open,in_progress,waiting,closed'],
        ]);

        $oldStatus = $ticket->status;

        $updateData = ['status' => $validated['status']];

        if ($validated['status'] === 'closed') {
            $updateData['resolved_at'] = now();
        }

        $ticket->update($updateData);

        // Notify the customer about the status change
        $ticket->user?->notify(new TicketStatusChangedNotification($ticket, $oldStatus, $validated['status']));

        AuditLog::query()->create([
            'user_id' => $ticket->user_id,
            'admin_id' => $request->user()->id,
            'action' => 'update_ticket_status',
            'resource_type' => 'support_ticket',
            'resource_id' => $ticket->id,
            'ip_address' => $request->ip(),
            'user_agent' => $request->userAgent(),
            'details' => json_encode(['status' => $validated['status']]),
        ]);

        return redirect()->back()->with('success', 'Ticket status updated.');
    }

    public function assign(Request $request, SupportTicket $ticket): RedirectResponse
    {
        $validated = $request->validate([
            'assigned_to' => ['nullable', 'exists:users,id'],
        ]);

        $ticket->update([
            'assigned_to' => $validated['assigned_to'],
        ]);

        AuditLog::query()->create([
            'user_id' => $ticket->user_id,
            'admin_id' => $request->user()->id,
            'action' => 'assign_ticket',
            'resource_type' => 'support_ticket',
            'resource_id' => $ticket->id,
            'ip_address' => $request->ip(),
            'user_agent' => $request->userAgent(),
            'details' => json_encode(['assigned_to' => $validated['assigned_to']]),
        ]);

        return redirect()->back()->with('success', 'Ticket assigned successfully.');
    }

    public function merge(Request $request, SupportTicket $ticket): RedirectResponse
    {
        $validated = $request->validate([
            'target_ticket_id' => ['required', 'exists:support_tickets,id', 'different:ticket.id'],
        ]);

        $targetTicket = SupportTicket::query()->findOrFail($validated['target_ticket_id']);

        // Move all replies from source to target
        $ticket->replies()->update(['ticket_id' => $targetTicket->id]);

        // Move tags
        $sourceTags = $ticket->tags()->pluck('ticket_tags.id')->toArray();
        $existingTargetTags = $targetTicket->tags()->pluck('ticket_tags.id')->toArray();
        $newTags = array_diff($sourceTags, $existingTargetTags);

        if (! empty($newTags)) {
            $targetTicket->tags()->attach($newTags);
        }

        // Mark source ticket as merged and closed
        $ticket->update([
            'merged_into_ticket_id' => $targetTicket->id,
            'status' => 'closed',
            'resolved_at' => now(),
        ]);

        // Add a system note on the target ticket
        TicketReply::query()->create([
            'ticket_id' => $targetTicket->id,
            'user_id' => $request->user()->id,
            'body' => "Ticket #{$ticket->id} ({$ticket->ticket_reference}) was merged into this ticket.",
            'is_staff_reply' => true,
            'is_internal' => true,
        ]);

        AuditLog::query()->create([
            'user_id' => $ticket->user_id,
            'admin_id' => $request->user()->id,
            'action' => 'merge_ticket',
            'resource_type' => 'support_ticket',
            'resource_id' => $ticket->id,
            'ip_address' => $request->ip(),
            'user_agent' => $request->userAgent(),
            'details' => json_encode(['merged_into' => $targetTicket->id]),
        ]);

        return redirect()->route('admin.tickets.show', $targetTicket)
            ->with('success', "Ticket #{$ticket->id} merged into #{$targetTicket->id}.");
    }

    public function updateTags(Request $request, SupportTicket $ticket): RedirectResponse
    {
        $validated = $request->validate([
            'tags' => ['array'],
            'tags.*' => ['integer', 'exists:ticket_tags,id'],
        ]);

        $ticket->tags()->sync($validated['tags'] ?? []);

        return redirect()->back()->with('success', 'Tags updated successfully.');
    }
}
