<?php

declare(strict_types=1);

namespace App\Services\Tickets;

use App\Models\SupportTicket;
use App\Models\TicketReply;
use App\Models\User;
use App\Notifications\TicketCreatedNotification;
use App\Notifications\TicketCustomerReplyNotification;
use App\Notifications\TicketStaffReplyNotification;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;

class TicketEmailProcessor
{
    public function processEmail(ParsedEmail $email): void
    {
        $ticket = $this->findTicketFromEmail($email);

        if ($ticket) {
            $this->addReplyToTicket($ticket, $email);
        } else {
            $this->createNewTicket($email);
        }
    }

    public function findTicketFromEmail(ParsedEmail $email): ?SupportTicket
    {
        // Strategy 1: Match by In-Reply-To header against ticket_replies.message_id
        if ($email->inReplyTo) {
            $reply = TicketReply::query()
                ->where('message_id', $email->inReplyTo)
                ->first();

            if ($reply) {
                return $reply->ticket;
            }
        }

        // Strategy 2: Match by References header against ticket_replies.message_id
        if ($email->references) {
            $referenceIds = preg_split('/\s+/', $email->references);
            if ($referenceIds) {
                $reply = TicketReply::query()
                    ->whereIn('message_id', $referenceIds)
                    ->latest()
                    ->first();

                if ($reply) {
                    return $reply->ticket;
                }
            }
        }

        // Strategy 3: Match by subject line ticket reference [EZSCALE-{id}]
        $regex = config('tickets.ticket_reference_regex');
        if (preg_match($regex, $email->subject, $matches)) {
            $ticketId = (int) $matches[1];

            return SupportTicket::query()->find($ticketId);
        }

        return null;
    }

    private function addReplyToTicket(SupportTicket $ticket, ParsedEmail $email): void
    {
        $isStaff = $this->isStaffEmail($email->from);
        $user = User::query()->where('email', $email->from)->first();

        $reply = TicketReply::query()->create([
            'ticket_id' => $ticket->id,
            'user_id' => $user?->id,
            'body' => $email->body,
            'is_staff_reply' => $isStaff,
            'message_id' => $email->messageId,
            'from_email' => $email->from,
            'via_email' => true,
        ]);

        $ticket->update([
            'last_reply_at' => now(),
            'status' => $ticket->status === 'closed' ? 'open' : $ticket->status,
        ]);

        // Send appropriate notifications
        if ($isStaff) {
            $ticket->user?->notify(new TicketStaffReplyNotification($ticket, $reply));
        } else {
            $admins = User::role('admin')->get();
            Notification::send($admins, new TicketCustomerReplyNotification($ticket, $reply));
        }

        Log::info('Email reply added to ticket', [
            'ticket_id' => $ticket->id,
            'from' => $email->from,
            'is_staff' => $isStaff,
        ]);
    }

    private function createNewTicket(ParsedEmail $email): void
    {
        $user = User::query()->where('email', $email->from)->first();

        $ticket = SupportTicket::query()->create([
            'user_id' => $user?->id,
            'customer_email' => $email->from,
            'subject' => $email->subject,
            'status' => 'open',
            'priority' => 'medium',
            'department' => config('tickets.default_department'),
            'last_reply_at' => now(),
        ]);

        TicketReply::query()->create([
            'ticket_id' => $ticket->id,
            'user_id' => $user?->id,
            'body' => $email->body,
            'is_staff_reply' => false,
            'message_id' => $email->messageId,
            'from_email' => $email->from,
            'via_email' => true,
        ]);

        // Notify admins about the new ticket
        $admins = User::role('admin')->get();
        Notification::send($admins, new TicketCreatedNotification($ticket));

        Log::info('New ticket created from email', [
            'ticket_id' => $ticket->id,
            'from' => $email->from,
            'subject' => $email->subject,
        ]);
    }

    public function isStaffEmail(string $email): bool
    {
        $user = User::query()->where('email', $email)->first();

        return $user?->hasRole('admin') ?? false;
    }
}
