<?php

namespace App\Http\Controllers\Webhooks\Communications;

use App\Enum\Contact\MessageChannel;
use App\Enum\Contact\MessageDirection;
use App\Enum\Contact\MessageProvider;
use App\Enum\Contact\MessageStatus;
use App\Http\Controllers\Controller;
use App\Jobs\Contact\ExtractMessageAttachmentsJob;
use App\Models\Contact\Hub\ContactMessage;
use App\Models\Contact\Hub\ContactMessageAttachment;
use App\Models\Solicitor\SolicitorEmailSender;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

class InboundEmailController extends Controller {
    public function __invoke(Request $request, string $token): Response {
        logger()->debug("Inbound email data", $request->all());

        $envelope = json_decode($request->input('envelope', '{}'), true);
        $toAddresses = array_map(function ($email) {
            return preg_replace('/@parse\./i', '@', $email);
        }, (array) ($envelope['to'] ?? []));
        $fromAddress = $envelope['from'] ?? $request->input('from', '');

        $fromAddress = $this->extractEmail($fromAddress);

        $sender = $this->resolveSender($toAddresses);
        if (!$sender) {
            return response('', 200);
        }

        $message = ContactMessage::create([
            'solicitor_id' => $sender->solicitor_id,
            'sender_email_id' => $sender->id,
            'channel' => MessageChannel::EMAIL,
            'direction' => MessageDirection::INBOUND,
            'provider' => MessageProvider::SENDGRID,
            'status' => MessageStatus::SENT,
            'from_email' => $fromAddress,
            'recipient_email' => $sender->email_address,
            'subject' => $request->input('subject'),
            'body_html' => $request->input('html'),
            'body_text' => $request->input('text'),
        ]);

        $this->storeAttachments($request, $message);

        // Extract text from any attachments first; the extraction job chains
        // to ClassifyInboundEmailJob when all attachments have been processed.
        ExtractMessageAttachmentsJob::dispatch($message->id);

        return response('', 200);
    }

    private function resolveSender(array $toAddresses): ?SolicitorEmailSender {
        foreach ($toAddresses as $raw) {
            $email = strtolower($this->extractEmail($raw));
            $sender = SolicitorEmailSender::where('email_address', $email)->first();
            if ($sender) {
                return $sender;
            }
        }
        return null;
    }

    private function extractEmail(string $raw): string {
        if (preg_match('/<([^>]+)>/', $raw, $m)) {
            return strtolower(trim($m[1]));
        }
        return strtolower(trim($raw));
    }

    private function storeAttachments(Request $request, ContactMessage $message): void {
        $attachmentCount = (int)$request->input('attachments', 0);
        if ($attachmentCount === 0) {
            return;
        }

        $info = json_decode($request->input('attachment-info', '{}'), true);

        for ($i = 1; $i <= $attachmentCount; $i++) {
            $file = $request->file("attachment{$i}");
            if (!$file) {
                continue;
            }

            $meta = $info["attachment{$i}"] ?? [];
            $filename = $meta['filename'] ?? $file->getClientOriginalName();
            $mime = $meta['type'] ?? $file->getMimeType();
            $size = $file->getSize();

            $path = $file->storeAs(
                "contact-attachments/{$message->id}",
                $filename,
                'local'
            );

            ContactMessageAttachment::create([
                'contact_message_id' => $message->id,
                'disk' => 'local',
                'path' => $path,
                'filename' => $filename,
                'mime' => $mime,
                'size' => $size,
            ]);
        }
    }
}
