<?php

declare(strict_types=1);

namespace Instinctor\Services;

use Instinctor\Core\Config;
use Instinctor\Core\DB;
use Instinctor\Core\Mailer;


if ( ! defined( 'ABSPATH' ) ) exit;

/**
 * Order Tracking Service
 * Manages shipment tracking with carrier integration
 */
class OrderTrackingService
{
    private static array $carriers = [
        'usps' => [
            'name' => 'USPS',
            'url' => 'https://tools.usps.com/go/TrackConfirmAction?tLabels=',
        ],
        'ups' => [
            'name' => 'UPS',
            'url' => 'https://www.ups.com/track?tracknum=',
        ],
        'fedex' => [
            'name' => 'FedEx',
            'url' => 'https://www.fedex.com/fedextrack/?trknbr=',
        ],
        'dhl' => [
            'name' => 'DHL',
            'url' => 'https://www.dhl.com/us-en/home/tracking/tracking-express.html?submit=1&tracking-id=',
        ],
        'amazon' => [
            'name' => 'Amazon Logistics',
            'url' => 'https://track.amazon.com/tracking/',
        ],
        'ontrac' => [
            'name' => 'OnTrac',
            'url' => 'https://www.ontrac.com/tracking/?number=',
        ],
        'lasership' => [
            'name' => 'LaserShip',
            'url' => 'https://www.lasership.com/track/',
        ],
        'canada_post' => [
            'name' => 'Canada Post',
            'url' => 'https://www.canadapost-postescanada.ca/track-reperer/en#/search?searchFor=',
        ],
        'royal_mail' => [
            'name' => 'Royal Mail',
            'url' => 'https://www.royalmail.com/track-your-item#/tracking-results/',
        ],
        'other' => [
            'name' => 'Other',
            'url' => '',
        ],
    ];

    private static array $statuses = [
        'pending' => 'Pending',
        'label_created' => 'Label Created',
        'picked_up' => 'Picked Up',
        'in_transit' => 'In Transit',
        'out_for_delivery' => 'Out for Delivery',
        'delivered' => 'Delivered',
        'failed' => 'Delivery Failed',
        'returned' => 'Returned',
    ];

    /**
     * Add tracking to order
     */
    public static function addTracking(array $data): ?int
    {
        $table = DB::prefix() . 'instinctor_order_tracking';

        $carrier = sanitize_text_field($data['carrier']);
        $trackingNumber = sanitize_text_field($data['tracking_number']);

        // Generate tracking URL if not provided
        $trackingUrl = !empty($data['tracking_url']) ? $data['tracking_url'] : self::generateTrackingUrl($carrier, $trackingNumber);

        $insertData = [
            'order_id' => intval($data['order_id']),
            'carrier' => $carrier,
            'tracking_number' => $trackingNumber,
            'tracking_url' => $trackingUrl,
            'status' => 'pending',
            'shipped_at' => current_time('mysql'),
        ];
        
        // Add estimated delivery if provided
        if (!empty($data['estimated_delivery'])) {
            $insertData['estimated_delivery'] = sanitize_text_field($data['estimated_delivery']);
        }

        DB::insert($table, $insertData);

        $id = DB::insert_id();

        // Update order status if needed
        if ($id) {
            self::updateOrderStatus(intval($data['order_id']), 'shipped');
            
            // Send notification
            if (!empty($data['notify_customer']) || Config::get('instinctor_auto_send_tracking', true)) {
                self::sendTrackingEmail(intval($data['order_id']));
            }
        }

        return $id ?: null;
    }

    /**
     * Get tracking for order
     */
    public static function getOrderTracking(int $orderId): array
    {
        $table = DB::prefix() . 'instinctor_order_tracking';

        $tracking = DB::get_results(DB::prepare(
            "SELECT * FROM $table WHERE order_id = %d ORDER BY created_at DESC",
            $orderId
        ));

        foreach ($tracking as &$t) {
            $t->carrier_name = self::$carriers[$t->carrier]['name'] ?? $t->carrier;
            $t->status_label = self::$statuses[$t->status] ?? $t->status;
        }

        return $tracking;
    }

    /**
     * Get tracking by ID
     */
    public static function getById(int $id): ?object
    {
        $table = DB::prefix() . 'instinctor_order_tracking';

        $tracking = DB::get_row(DB::prepare("SELECT * FROM $table WHERE id = %d", $id));

        if ($tracking) {
            $tracking->carrier_name = self::$carriers[$tracking->carrier]['name'] ?? $tracking->carrier;
            $tracking->status_label = self::$statuses[$tracking->status] ?? $tracking->status;
        }

        return $tracking;
    }

    /**
     * Update tracking status
     */
    public static function updateStatus(int $id, string $status, ?string $detail = null): bool
    {
        $table = DB::prefix() . 'instinctor_order_tracking';

        $update = [
            'status' => $status,
            'last_update' => current_time('mysql'),
        ];

        if ($detail) {
            $update['status_detail'] = $detail;
        }

        if ($status === 'delivered') {
            $update['delivered_at'] = current_time('mysql');
        }

        $result = DB::update($table, $update, ['id' => $id]);

        // Update order status if delivered
        if ($result !== false && $status === 'delivered') {
            $tracking = self::getById($id);
            if ($tracking) {
                self::updateOrderStatus($tracking->order_id, 'completed');
            }
        }

        return $result !== false;
    }

    /**
     * Update estimated delivery
     */
    public static function updateEstimatedDelivery(int $id, string $date): bool
    {
        $table = DB::prefix() . 'instinctor_order_tracking';

        return DB::update($table, [
            'estimated_delivery' => $date,
        ], ['id' => $id]) !== false;
    }

    /**
     * Delete tracking
     */
    public static function delete(int $id): bool
    {
        $table = DB::prefix() . 'instinctor_order_tracking';

        return DB::delete($table, ['id' => $id]) !== false;
    }

    /**
     * Generate tracking URL
     */
    public static function generateTrackingUrl(string $carrier, string $trackingNumber): string
    {
        $baseUrl = self::$carriers[$carrier]['url'] ?? '';
        
        if (empty($baseUrl)) {
            return '';
        }

        return $baseUrl . urlencode($trackingNumber);
    }

    /**
     * Get available carriers
     */
    public static function getCarriers(): array
    {
        return self::$carriers;
    }

    /**
     * Get available statuses
     */
    public static function getStatuses(): array
    {
        return self::$statuses;
    }

    /**
     * Update order status
     */
    private static function updateOrderStatus(int $orderId, string $status): void
    {
        $table = DB::prefix() . 'instinctor_orders';

        DB::update($table, ['status' => $status], ['id' => $orderId]);

        // Add order note
        OrderNoteService::addNote($orderId, 'Order status changed to ' . $status, false);
    }

    /**
     * Send tracking email
     */
    public static function sendTrackingEmail(int $orderId): bool
    {
        $p = DB::prefix();
        
        $order = DB::get_row(DB::prepare(
            "SELECT o.*, c.email, c.first_name 
             FROM {$p}instinctor_orders o
             LEFT JOIN {$p}instinctor_customers c ON o.customer_id = c.id
             WHERE o.id = %d",
            $orderId
        ));

        if (!$order || !$order->email) {
            return false;
        }

        $tracking = self::getOrderTracking($orderId);
        
        if (empty($tracking)) {
            return false;
        }

        $subject = sprintf('Your order #%s has shipped!', $order->order_number);
        $message = self::getEmailTemplate($order, $tracking);

        return Mailer::html($order->email, $subject, $message);
    }

    /**
     * Get email template
     */
    private static function getEmailTemplate(object $order, array $tracking): string
    {
        $siteName = get_bloginfo('name');
        
        ob_start();
        ?>
        <!DOCTYPE html>
        <html>
        <head>
            <style>
                body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; padding: 20px; background: #f5f5f7; }
                .container { max-width: 600px; margin: 0 auto; }
                .header { background: #1d1d1f; color: #fff; padding: 30px; text-align: center; border-radius: 8px 8px 0 0; }
                .body { padding: 30px; background: #fff; }
                .footer { padding: 20px; text-align: center; font-size: 12px; color: #666; background: #fff; border-radius: 0 0 8px 8px; }
                .tracking-box { background: #f5f5f7; padding: 20px; border-radius: 8px; margin: 20px 0; }
                .tracking-number { font-size: 24px; font-family: monospace; margin: 10px 0; }
                .track-btn { display: inline-block; background: #1d1d1f; color: #fff; padding: 12px 24px; text-decoration: none; border-radius: 6px; margin-top: 15px; }
            </style>
        </head>
        <body>
            <div class="container">
                <div class="header">
                    <h1>📦 Your Order Has Shipped!</h1>
                </div>
                <div class="body">
                    <p>Hi <?php echo esc_html($order->first_name ?: 'there'); ?>,</p>
                    <p>Great news! Your order <strong>#<?php echo esc_html($order->order_number); ?></strong> is on its way.</p>
                    
                    <?php foreach ($tracking as $t): ?>
                    <div class="tracking-box">
                        <p><strong>Carrier:</strong> <?php echo esc_html($t->carrier_name); ?></p>
                        <p><strong>Tracking Number:</strong></p>
                        <div class="tracking-number"><?php echo esc_html($t->tracking_number); ?></div>
                        <?php if ($t->estimated_delivery): ?>
                        <p><strong>Estimated Delivery:</strong> <?php echo esc_html( date('l, F j, Y', strtotime($t->estimated_delivery)) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date -- intentional local-time display ?></p>
                        <?php endif; ?>
                        <?php if ($t->tracking_url): ?>
                        <a href="<?php echo esc_url($t->tracking_url); ?>" class="track-btn">Track Your Package</a>
                        <?php endif; ?>
                    </div>
                    <?php endforeach; ?>
                </div>
                <div class="footer">
                    <p>Thank you for shopping with <?php echo esc_html($siteName); ?>!</p>
                </div>
            </div>
        </body>
        </html>
        <?php
        return ob_get_clean();
    }

    /**
     * Get tracking page HTML for customers
     */
    public static function getTrackingPageHtml(int $orderId): string
    {
        $tracking = self::getOrderTracking($orderId);
        
        if (empty($tracking)) {
            return '<p>No tracking information available yet.</p>';
        }

        ob_start();
        ?>
        <div class="instinctor-tracking">
            <?php foreach ($tracking as $t): ?>
            <div class="instinctor-tracking-item">
                <div class="instinctor-tracking-header">
                    <span class="instinctor-carrier"><?php echo esc_html($t->carrier_name); ?></span>
                    <span class="instinctor-status instinctor-status-<?php echo esc_attr($t->status); ?>">
                        <?php echo esc_html($t->status_label); ?>
                    </span>
                </div>
                <div class="instinctor-tracking-number">
                    <?php echo esc_html($t->tracking_number); ?>
                </div>
                <?php if ($t->estimated_delivery): ?>
                <div class="instinctor-estimated-delivery">
                    <strong>Estimated delivery:</strong> <?php echo esc_html( date('F j, Y', strtotime($t->estimated_delivery)) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date -- intentional local-time display ?>
                </div>
                <?php endif; ?>
                <?php if ($t->tracking_url): ?>
                <a href="<?php echo esc_url($t->tracking_url); ?>" target="_blank" class="instinctor-btn instinctor-btn-secondary">
                    Track Package →
                </a>
                <?php endif; ?>
                <?php if ($t->status_detail): ?>
                <div class="instinctor-tracking-detail">
                    <?php echo esc_html($t->status_detail); ?>
                </div>
                <?php endif; ?>
            </div>
            <?php endforeach; ?>
        </div>
        <?php
        return ob_get_clean();
    }

    /**
     * Fetch tracking updates from carrier API (if configured)
     * This is a stub for future carrier API integration
     */
    public static function fetchUpdates(int $trackingId): bool
    {
        $tracking = self::getById($trackingId);
        
        if (!$tracking) {
            return false;
        }

        // Future: Implement actual carrier API calls
        // For now, this is a placeholder
        
        return true;
    }

    /**
     * Bulk update tracking status (cron job for carrier API updates)
     */
    public static function bulkFetchUpdates(): int
    {
        $table = DB::prefix() . 'instinctor_order_tracking';

        // Get all non-delivered tracking
        $pending = DB::get_results(
            "SELECT id FROM $table WHERE status NOT IN ('delivered', 'returned', 'failed')"
        );

        $updated = 0;
        foreach ($pending as $t) {
            if (self::fetchUpdates($t->id)) {
                $updated++;
            }
        }

        return $updated;
    }

    /**
     * Public order lookup by order number and email
     * Used by frontend tracking form
     */
    public static function lookupOrder(string $orderNumber, string $email): ?array
    {
        $p = DB::prefix();
        
        $orderNumber = sanitize_text_field($orderNumber);
        $email = sanitize_email($email);
        
        if (empty($orderNumber) || empty($email)) {
            return null;
        }
        
        // Find order matching both order number and customer email
        $order = DB::get_row(DB::prepare(
            "SELECT o.*, c.email, c.first_name, c.last_name
             FROM {$p}instinctor_orders o
             LEFT JOIN {$p}instinctor_customers c ON o.customer_id = c.id
             WHERE o.order_number = %s AND c.email = %s",
            $orderNumber,
            $email
        ));
        
        if (!$order) {
            return null;
        }
        
        // Get tracking info from tracking table
        $tracking = self::getOrderTracking($order->id);
        
        // Fallback: if no tracking table rows, check orders.meta for legacy data
        if (empty($tracking)) {
            $meta = json_decode($order->meta ?? '{}', true);
            if (!empty($meta['tracking_number'])) {
                $carrierKey = $meta['tracking_carrier'] ?? 'other';
                $carrierName = self::$carriers[$carrierKey]['name'] ?? $carrierKey;
                $tracking = [(object)[
                    'carrier' => $carrierKey,
                    'carrier_name' => $carrierName,
                    'tracking_number' => $meta['tracking_number'],
                    'tracking_url' => $meta['tracking_url'] ?? self::generateTrackingUrl($carrierKey, $meta['tracking_number']),
                    'status' => 'in_transit',
                    'status_label' => 'In Transit',
                    'estimated_delivery' => null,
                    'shipped_at' => null,
                ]];
            }
        }
        
        // Get order items
        $items = DB::get_results(DB::prepare(
            "SELECT oi.*, p.name as product_name
             FROM {$p}instinctor_order_items oi
             LEFT JOIN {$p}instinctor_products p ON oi.product_id = p.id
             WHERE oi.order_id = %d",
            $order->id
        ));
        
        return [
            'order' => $order,
            'tracking' => $tracking,
            'items' => $items,
        ];
    }
}
