<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\App;
use Mtc\Core\Models\Country;
use Mtc\Core\Models\CountryState;

class TestEmailCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'email:test
                            {to : Comma-separated recipient email address(es)}
                            {--template=contact : Comma-separated template key(s), or "all"}
                            {--order= : Order ID (required for shop templates)}
                            {--name=Test Person : Sender full name (contact templates)}
                            {--from=sender@example.com : Sender email address (used as reply-to)}
                            {--telephone=01234 567890 : Sender telephone (contact template)}
                            {--reason=General enquiry : Reason for contacting (contact template)}
                            {--message=This is a test message.\nSecond line. : Message body (contact templates)}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Render and send pharmacy email templates to specific address(es) for testing';

    /**
     * Execute the console command.
     */
    public function handle(): int
    {
        // The email templates and legacy classes were written for a web request and read
        // $_SERVER['HTTP_HOST'] (e.g. core/classes/class.util.php) to build absolute URLs.
        // That key is absent in CLI, so seed the request vars from the configured app URL.
        $this->seedServerVars();

        $registry = $this->templateRegistry();

        // 1. Parse and validate recipients.
        $recipients = array_filter(array_map('trim', explode(',', (string) $this->argument('to'))));
        if (empty($recipients)) {
            $this->error('No recipients provided.');
            return self::FAILURE;
        }
        foreach ($recipients as $recipient) {
            if (!filter_var($recipient, FILTER_VALIDATE_EMAIL)) {
                $this->error("\"{$recipient}\" is not a valid email address.");
                return self::FAILURE;
            }
        }

        // 2. Resolve the selected template keys.
        $selection = strtolower(trim((string) $this->option('template')));
        if ($selection === 'all') {
            $keys = array_keys($registry);
        } else {
            $keys = array_filter(array_map('trim', explode(',', $selection)));
            foreach ($keys as $key) {
                if (!isset($registry[$key])) {
                    $this->error("Unknown template key \"{$key}\". Available: " . implode(', ', array_keys($registry)) . ', all');
                    return self::FAILURE;
                }
            }
        }
        if (empty($keys)) {
            $this->error('No templates selected.');
            return self::FAILURE;
        }

        // 3. If any selected template needs an order, load it once.
        $needs_order = false;
        foreach ($keys as $key) {
            if (!empty($registry[$key]['needs_order'])) {
                $needs_order = true;
            }
        }

        $base_options = null;
        if ($needs_order) {
            $order_id = $this->option('order');
            if (empty($order_id) || !is_numeric($order_id)) {
                $this->error('A valid --order=ID is required for shop templates (' . $this->shopKeys($registry) . ').');
                return self::FAILURE;
            }

            // The legacy Order class uses the standalone Eloquent Capsule, which is normally
            // booted by core/includes/header.inc.php. That header does not run during artisan
            // commands, so set the Capsule up here (require_once is a no-op if already loaded).
            $this->bootLegacyDatabase();

            $order = \Order::getById($order_id);
            if (!is_object($order)) {
                $this->error("Order ID {$order_id} does not exist.");
                return self::FAILURE;
            }

            $base_options = $this->buildOrderOptions($order);
        }

        // 4. Render and send each template to each recipient.
        $rows = [];
        $had_failure = false;
        $twig = App::make('twig');
        $from = $this->option('from');

        foreach ($keys as $key) {
            $definition = $registry[$key];
            $context = $definition['context']($base_options);

            try {
                $body = $twig->render($definition['path'], $context);
            } catch (\Throwable $e) {
                foreach ($recipients as $recipient) {
                    $rows[] = [$key, $recipient, 'RENDER FAIL: ' . $e->getMessage()];
                }
                $had_failure = true;
                continue;
            }

            foreach ($recipients as $recipient) {
                $sent = email($recipient, $definition['subject'], $body, ['reply_to' => $from]);
                if ($sent) {
                    $rows[] = [$key, $recipient, 'sent'];
                } else {
                    $rows[] = [$key, $recipient, 'SEND FAIL'];
                    $had_failure = true;
                }
            }
        }

        $this->table(['Template', 'Recipient', 'Result'], $rows);

        if (DEV_MODE) {
            $this->line('Running in DEV mode: mail is intercepted by MailHog (this project: http://localhost:8026).');
        }

        return $had_failure ? self::FAILURE : self::SUCCESS;
    }

    /**
     * Registry of testable templates keyed by a short CLI key.
     *
     * @return array<string, array{path: string, subject: string, needs_order: bool, context: callable}>
     */
    private function templateRegistry(): array
    {
        return [
            'contact' => [
                'path' => 'emails/contact_email/contact_email.twig',
                'subject' => 'New Enquiry from ' . $this->option('name') . ' (TEST)',
                'needs_order' => false,
                'context' => fn ($base) => [
                    'validated_inputs' => [
                        'full_name' => $this->option('name'),
                        'email' => $this->option('from'),
                        'telephone' => $this->option('telephone'),
                        'reason' => $this->option('reason'),
                        'message' => str_replace('\n', "\n", $this->option('message')),
                    ],
                ],
            ],
            'password_reset' => [
                'path' => 'emails/password_reset_new_website/password_reset_new_website.twig',
                'subject' => 'Reset your password (TEST)',
                'needs_order' => false,
                'context' => fn ($base) => [
                    'url' => rtrim((string) config('site.url', config('app.url')), '/') . '/reset-password?token=TEST-TOKEN',
                ],
            ],
            'order' => [
                'path' => 'emails/shop/order_email.twig',
                'subject' => 'Your order confirmation (TEST)',
                'needs_order' => true,
                'context' => fn ($base) => $this->orderContext($base, 0),
            ],
            'shipment' => [
                'path' => 'emails/shop/shipment_email.twig',
                'subject' => 'Your order has shipped (TEST)',
                'needs_order' => true,
                'context' => fn ($base) => $this->orderContext($base, 4),
            ],
            'refund' => [
                'path' => 'emails/shop/refund.twig',
                'subject' => 'Your refund (TEST)',
                'needs_order' => true,
                'context' => fn ($base) => $this->orderContext($base, 6),
            ],
            'partial_refund' => [
                'path' => 'emails/shop/partial_refund.twig',
                'subject' => 'Your partial refund (TEST)',
                'needs_order' => true,
                'context' => fn ($base) => $this->orderContext($base, 6),
            ],
            'shop_contact' => [
                'path' => 'emails/shop/contact_email.twig',
                'subject' => 'A message about your order (TEST)',
                'needs_order' => true,
                'context' => fn ($base) => $this->orderContext($base, 0) + [
                    'subject' => 'A message about your order (TEST)',
                    'html' => '<p>This is a sample message to show a customer message.</p>'
                        . '<p>This is a sample paragraph to show a paragraph being replaced with the correct styles.</p>',
                ],
            ],
            'pre_payment' => [
                'path' => 'emails/shop/pre_payment.twig',
                'subject' => 'Complete your order (TEST)',
                'needs_order' => true,
                'context' => fn ($base) => $this->orderContext($base, 0),
            ],
        ];
    }

    /**
     * Seed the $_SERVER request vars that web-oriented templates and legacy classes expect,
     * deriving the host from the configured app URL. Existing values are left untouched.
     */
    private function seedServerVars(): void
    {
        $url = (string) config('app.url');
        $host = parse_url($url, PHP_URL_HOST) ?: 'localhost';
        $is_https = str_starts_with($url, 'https://');

        $_SERVER['HTTP_HOST'] ??= $host;
        $_SERVER['SERVER_NAME'] ??= $host;
        $_SERVER['SERVER_PORT'] ??= ($is_https ? 443 : 80);
        $_SERVER['REQUEST_URI'] ??= '/';
        if ($is_https) {
            $_SERVER['HTTPS'] ??= 'on';
        }
    }

    /**
     * Boot the legacy Eloquent Capsule used by global-namespace classes such as Order.
     */
    private function bootLegacyDatabase(): void
    {
        $app = App::getFacadeRoot();
        require_once base_path('core/includes/eloquent.php');
    }

    /**
     * Build the base order options array (mirrors shop/admin/emails.php).
     */
    private function buildOrderOptions(\Order $order): array
    {
        return [
            'order' => $order,
            'line_items' => $order->getLineItems(),
            'order_subtotal' => $order->getSubtotalCost(),
            'order_total' => $order->getTotalCost(),
            'vat_cost' => $order->getVatCost(),
            'order_date' => $order->getOrderDate('Y-m-d H:i:s'),
            'delivery_cost' => $order->getDelivery()->cost,
            'delivery_name' => $order->getDelivery()->name,
            'order_status_text' => '',
            'countries' => Country::getCountryList(),
            'state_list' => CountryState::getCountryStateList(),
        ];
    }

    /**
     * Clone the base order options and apply the status text for the given status id.
     */
    private function orderContext(array $base, int $status_id): array
    {
        $base['order_status_text'] = $base['order']->getOrderStatusText($status_id);
        return $base;
    }

    /**
     * Comma-separated list of shop (order-dependent) template keys, for error messages.
     */
    private function shopKeys(array $registry): string
    {
        return implode(', ', array_keys(array_filter($registry, fn ($d) => !empty($d['needs_order']))));
    }
}
