<?php

namespace App\Services;

use App\Models\Order;
use App\Models\Setting;
use App\Mail\OrderInvoiceMail;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Log;

class NotificationDispatcher
{
    /**
     * Dispatch notifications for a newly placed/confirmed order.
     */
    public static function dispatchOrderPlaced(Order $order)
    {
        Log::info('Dispatching Order Placed notifications for #' . $order->order_number);

        // 1. Send Customer SMS
        if (Setting::getValue('sms_order_placed_enabled', true)) {
            $smsTemplate = Setting::getValue(
                'sms_template_order_placed',
                'Hello {customer_name}, your order #{order_number} has been confirmed. Total is ৳{grand_total}. Thanks for shopping with {site_name}!'
            );

            $smsMessage = self::parseShortcodes($smsTemplate, $order);
            SmsService::sendSms($order->customer_phone, $smsMessage, $order->id);
        }

        // 2. Send Customer Email
        if ($order->customer_email && Setting::getValue('email_order_placed_enabled', true)) {
            self::sendEmail(
                $order->customer_email,
                new OrderInvoiceMail($order, 'placed'),
                $order,
                'placed',
                "Order Invoice Email (placed) - #{$order->order_number}"
            );
        }

        // 3. Send Admin Alerts
        self::dispatchAdminAlerts($order);

        // 4. Send Database Notification to Admins (synchronously via notifyNow)
        try {
            $admins = \App\Models\User::where('role', 'admin')->get();
            if ($admins->count() > 0) {
                $dbNotification = \Filament\Notifications\Notification::make()
                    ->title('New Order Placed')
                    ->body("Order #{$order->order_number} has been placed by {$order->customer_name} for BDT " . number_format($order->grand_total, 2))
                    ->icon('heroicon-o-shopping-bag')
                    ->iconColor('success')
                    ->actions([
                        \Filament\Actions\Action::make('view')
                            ->label('View Order')
                            ->button()
                            ->color('primary')
                            ->markAsRead()
                            ->url(\App\Filament\Resources\Orders\OrderResource::getUrl('edit', ['record' => $order])),
                    ])
                    ->toDatabase();
                foreach ($admins as $admin) {
                    $admin->notifyNow($dbNotification);
                }
            }
        } catch (\Exception $e) {
            Log::error('Failed to send database notification for new order: ' . $e->getMessage());
        }
    }

    /**
     * Dispatch notifications when an order is shipped.
     */
    public static function dispatchOrderShipped(Order $order)
    {
        Log::info('Dispatching Order Shipped notifications for #' . $order->order_number);

        $order->load('courierBooking');

        // 1. Send Customer SMS
        if (Setting::getValue('sms_order_shipped_enabled', true)) {
            $smsTemplate = Setting::getValue(
                'sms_template_order_shipped',
                'Hello {customer_name}, your order #{order_number} has been shipped via {courier_name}. Tracking: {tracking_code}. Track here: {tracking_link}'
            );

            $smsMessage = self::parseShortcodes($smsTemplate, $order);
            SmsService::sendSms($order->customer_phone, $smsMessage, $order->id);
        }

        // 2. Send Customer Email
        if ($order->customer_email && Setting::getValue('email_order_shipped_enabled', true)) {
            self::sendEmail(
                $order->customer_email,
                new OrderInvoiceMail($order, 'shipped'),
                $order,
                'shipped',
                "Order Shipped Email - #{$order->order_number}"
            );
        }
    }

    /**
     * Dispatch notifications when an order is delivered.
     */
    public static function dispatchOrderDelivered(Order $order)
    {
        Log::info('Dispatching Order Delivered notifications for #' . $order->order_number);

        // 1. Send Customer SMS
        if (Setting::getValue('sms_order_delivered_enabled', true)) {
            $smsTemplate = Setting::getValue(
                'sms_template_order_delivered',
                'Dear {customer_name}, your order #{order_number} has been delivered successfully. Thank you for choosing us!'
            );

            $smsMessage = self::parseShortcodes($smsTemplate, $order);
            SmsService::sendSms($order->customer_phone, $smsMessage, $order->id);
        }

        // 2. Send Customer Email
        if ($order->customer_email && Setting::getValue('email_order_delivered_enabled', true)) {
            self::sendEmail(
                $order->customer_email,
                new OrderInvoiceMail($order, 'delivered'),
                $order,
                'delivered',
                "Order Delivered Email - #{$order->order_number}"
            );
        }
    }

    /**
     * Dispatch notifications when an order is cancelled.
     */
    public static function dispatchOrderCancelled(Order $order)
    {
        Log::info('Dispatching Order Cancelled notifications for #' . $order->order_number);

        // 1. Send Customer SMS
        if (Setting::getValue('sms_order_cancelled_enabled', true)) {
            $smsTemplate = Setting::getValue(
                'sms_template_order_cancelled',
                'Dear {customer_name}, your order #{order_number} has been cancelled. Please contact us for more info.'
            );

            $smsMessage = self::parseShortcodes($smsTemplate, $order);
            SmsService::sendSms($order->customer_phone, $smsMessage, $order->id);
        }

        // 2. Send Customer Email
        if ($order->customer_email && Setting::getValue('email_order_cancelled_enabled', true)) {
            self::sendEmail(
                $order->customer_email,
                new OrderInvoiceMail($order, 'cancelled'),
                $order,
                'cancelled',
                "Order Cancelled Email - #{$order->order_number}"
            );
        }
    }

    /**
     * Dispatch notifications when online payment is successfully received.
     */
    public static function dispatchPaymentReceived(Order $order)
    {
        Log::info('Dispatching Payment Received notifications for #' . $order->order_number);

        // 1. Send Customer SMS
        if (Setting::getValue('sms_payment_received_enabled', true)) {
            $smsTemplate = Setting::getValue(
                'sms_template_payment_received',
                'Dear {customer_name}, we have received your payment of ৳{grand_total} for order #{order_number}. Thank you!'
            );

            $smsMessage = self::parseShortcodes($smsTemplate, $order);
            SmsService::sendSms($order->customer_phone, $smsMessage, $order->id);
        }

        // 2. Send Customer Email
        if ($order->customer_email && Setting::getValue('email_payment_received_enabled', true)) {
            self::sendEmail(
                $order->customer_email,
                new OrderInvoiceMail($order, 'payment_received'),
                $order,
                'payment_received',
                "Payment Received Email - #{$order->order_number}"
            );
        }

        // 3. Send Database Notification to Admins (synchronously via notifyNow)
        try {
            $admins = \App\Models\User::where('role', 'admin')->get();
            if ($admins->count() > 0) {
                $dbNotification = \Filament\Notifications\Notification::make()
                    ->title('Payment Received')
                    ->body("Payment of BDT " . number_format($order->grand_total, 2) . " received for Order #{$order->order_number}")
                    ->icon('heroicon-o-credit-card')
                    ->iconColor('success')
                    ->actions([
                        \Filament\Actions\Action::make('view')
                            ->label('View Order')
                            ->button()
                            ->color('primary')
                            ->markAsRead()
                            ->url(\App\Filament\Resources\Orders\OrderResource::getUrl('edit', ['record' => $order])),
                    ])
                    ->toDatabase();
                foreach ($admins as $admin) {
                    $admin->notifyNow($dbNotification);
                }
            }
        } catch (\Exception $e) {
            Log::error('Failed to send database notification for payment received: ' . $e->getMessage());
        }
    }

    /**
     * Dispatch notifications when payment fails.
     */
    public static function dispatchPaymentFailed(Order $order)
    {
        Log::info('Dispatching Payment Failed notifications for #' . $order->order_number);

        // Send Database Notification to Admins
        try {
            $admins = \App\Models\User::where('role', 'admin')->get();
            if ($admins->count() > 0) {
                $dbNotification = \Filament\Notifications\Notification::make()
                    ->title('Payment Failed')
                    ->body("Payment failed for Order #{$order->order_number} by {$order->customer_name}")
                    ->icon('heroicon-o-x-circle')
                    ->iconColor('danger')
                    ->actions([
                        \Filament\Actions\Action::make('view')
                            ->label('View Order')
                            ->button()
                            ->color('primary')
                            ->markAsRead()
                            ->url(\App\Filament\Resources\Orders\OrderResource::getUrl('edit', ['record' => $order])),
                    ])
                    ->toDatabase();
                foreach ($admins as $admin) {
                    $admin->notifyNow($dbNotification);
                }
            }
        } catch (\Exception $e) {
            Log::error('Failed to send database notification for payment failure: ' . $e->getMessage());
        }
    }

    /**
     * Dispatch notifications when payment is refunded.
     */
    public static function dispatchPaymentRefunded(Order $order)
    {
        Log::info('Dispatching Payment Refunded notifications for #' . $order->order_number);

        // Send Database Notification to Admins
        try {
            $admins = \App\Models\User::where('role', 'admin')->get();
            if ($admins->count() > 0) {
                $dbNotification = \Filament\Notifications\Notification::make()
                    ->title('Payment Refunded')
                    ->body("Payment refunded for Order #{$order->order_number} of BDT " . number_format($order->grand_total, 2))
                    ->icon('heroicon-o-arrow-uturn-left')
                    ->iconColor('info')
                    ->actions([
                        \Filament\Actions\Action::make('view')
                            ->label('View Order')
                            ->button()
                            ->color('primary')
                            ->markAsRead()
                            ->url(\App\Filament\Resources\Orders\OrderResource::getUrl('edit', ['record' => $order])),
                    ])
                    ->toDatabase();
                foreach ($admins as $admin) {
                    $admin->notifyNow($dbNotification);
                }
            }
        } catch (\Exception $e) {
            Log::error('Failed to send database notification for payment refund: ' . $e->getMessage());
        }
    }

    /**
     * Dispatch admin alert notifications.
     */
    private static function dispatchAdminAlerts(Order $order)
    {
        // 1. Admin SMS alert
        if (Setting::getValue('admin_order_placed_sms_enabled', false)) {
            $adminPhone = Setting::getValue('admin_notification_phone');
            if ($adminPhone) {
                $smsTemplate = Setting::getValue(
                    'sms_template_admin_order_placed',
                    'New order #{order_number} placed by {customer_name}. Total: ৳{grand_total}.'
                );

                $smsMessage = self::parseShortcodes($smsTemplate, $order);
                SmsService::sendSms($adminPhone, $smsMessage, $order->id);
            }
        }

        // 2. Admin Email alert
        if (Setting::getValue('admin_order_placed_email_enabled', false)) {
            $adminEmail = Setting::getValue('admin_notification_email');
            if ($adminEmail) {
                self::sendEmail(
                    $adminEmail,
                    new OrderInvoiceMail($order, 'placed', true),
                    $order,
                    'placed_admin',
                    "Admin Alert: New Order Received - #{$order->order_number}"
                );
            }
        }
    }

    public static function dispatchForOrder(Order $order, string $status)
    {
        // Trigger channel-specific dispatchers (SMS/Email) based on status
        match ($status) {
            'shipped'   => self::dispatchOrderShipped($order),
            'delivered' => self::dispatchOrderDelivered($order),
            'cancelled' => self::dispatchOrderCancelled($order),
            default     => null,
        };

        // Admin database notification — correct title/body/icon per status
        $notificationConfig = match ($status) {
            'processing' => [
                'title'     => 'Order In Processing',
                'body'      => "Order #{$order->order_number} for {$order->customer_name} is now being processed.",
                'icon'      => 'heroicon-o-cog-6-tooth',
                'iconColor' => 'warning',
            ],
            'shipped' => [
                'title'     => 'Order Shipped',
                'body'      => "Order #{$order->order_number} for {$order->customer_name} has been shipped.",
                'icon'      => 'heroicon-o-truck',
                'iconColor' => 'info',
            ],
            'delivered' => [
                'title'     => 'Order Delivered',
                'body'      => "Order #{$order->order_number} for {$order->customer_name} has been delivered.",
                'icon'      => 'heroicon-o-check-badge',
                'iconColor' => 'success',
            ],
            'cancelled' => [
                'title'     => 'Order Cancelled',
                'body'      => "Order #{$order->order_number} for {$order->customer_name} has been cancelled.",
                'icon'      => 'heroicon-o-x-circle',
                'iconColor' => 'danger',
            ],
            default => [
                'title'     => 'Order Status Updated',
                'body'      => "Order #{$order->order_number} status updated to " . ucfirst($status) . '.',
                'icon'      => 'heroicon-o-arrow-path',
                'iconColor' => 'gray',
            ],
        };

        try {
            $admins = \App\Models\User::where('role', 'admin')->get();
            if ($admins->count() > 0) {
                $dbNotification = \Filament\Notifications\Notification::make()
                    ->title($notificationConfig['title'])
                    ->body($notificationConfig['body'])
                    ->icon($notificationConfig['icon'])
                    ->iconColor($notificationConfig['iconColor'])
                    ->actions([
                        \Filament\Actions\Action::make('view')
                            ->label('View Order')
                            ->button()
                            ->color('primary')
                            ->markAsRead()
                            ->url(\App\Filament\Resources\Orders\OrderResource::getUrl('edit', ['record' => $order])),
                    ])
                    ->toDatabase();
                foreach ($admins as $admin) {
                    $admin->notifyNow($dbNotification);
                }
            }
        } catch (\Exception $e) {
            Log::error('Failed to send database notification for order status update: ' . $e->getMessage());
        }
    }

    /**
     * Send and log customer/admin emails to notification_logs.
     */
    private static function sendEmail(string $recipient, OrderInvoiceMail $mailable, Order $order, string $status, string $messagePreview)
    {
        try {
            Mail::to($recipient)->queue($mailable);

            \App\Models\NotificationLog::create([
                'order_id' => $order->id,
                'type' => 'email',
                'channel' => 'smtp',
                'recipient' => $recipient,
                'message_preview' => $messagePreview,
                'status' => 'sent',
                'error_message' => null,
            ]);
        } catch (\Exception $e) {
            Log::error("Failed to send email to {$recipient}: " . $e->getMessage());

            try {
                \App\Models\NotificationLog::create([
                    'order_id' => $order->id,
                    'type' => 'email',
                    'channel' => 'smtp',
                    'recipient' => $recipient,
                    'message_preview' => $messagePreview,
                    'status' => 'failed',
                    'error_message' => $e->getMessage(),
                ]);
            } catch (\Exception $dbEx) {
                Log::error('Failed to log email failure: ' . $dbEx->getMessage());
            }
        }
    }

    /**
     * Parse shortcodes dynamically.
     */
    public static function parseShortcodes(string $template, Order $order): string
    {
        $siteName = Setting::getValue('site_name', 'Sawdabazar');
        
        $courierName = $order->courierBooking?->courier_name ?? 'Courier';
        $trackingCode = $order->courierBooking?->tracking_code ?? 'N/A';
        $trackingLink = route('dashboard') . '?orderNumber=' . $order->order_number . '&phone=' . $order->customer_phone;

        // Render the product list table
        $productListHtml = '';
        try {
            $order->loadMissing('items.product');
            $productListHtml = view('emails.partials.product_list', ['order' => $order])->render();
        } catch (\Exception $e) {
            Log::error('Failed to render product list partial inside email shortcodes: ' . $e->getMessage());
        }

        // If {product_list} is not inside the template, append it automatically
        if (!str_contains($template, '{product_list}')) {
            $template .= "\n\n{product_list}";
        }

        // Safe conversion: escape user input, map newlines to <br>, parse **bold** markdown to <strong>
        $templateHtml = nl2br(e($template));
        $templateHtml = preg_replace('/\*\*(.*?)\*\*/', '<strong>$1</strong>', $templateHtml);

        $replacements = [
            '{customer_name}' => e($order->customer_name),
            '{order_number}' => e($order->order_number),
            '{grand_total}' => number_format($order->grand_total, 2),
            '{site_name}' => e($siteName),
            '{courier_name}' => e(ucfirst($courierName)),
            '{tracking_code}' => e($trackingCode),
            '{tracking_link}' => e($trackingLink),
            '{product_list}' => $productListHtml,
        ];

        return str_replace(array_keys($replacements), array_values($replacements), $templateHtml);
    }
}
