<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use App\Helpers\PoslajuValidator;
use App\Models\PoslajuSetting;
use App\Models\User;
use Exception;

class PoslajuService
{
    protected $apiUrl;
    protected $settings;

    public function __construct($userId = null)
    {
        // Get settings from database first
        if ($userId) {
            $this->settings = PoslajuSetting::where('user_id', $userId)->first();
        } else {
            // Try to get settings from auth user or first active setting
            $this->settings = auth()->check()
                ? PoslajuSetting::where('user_id', auth()->id())->first()
                : PoslajuSetting::where('is_active', true)->first();
        }

        // Set API URL based on test mode setting
        if ($this->settings && $this->settings->test_mode) {
            $this->apiUrl = 'https://api-dev.pos.com.my'; // Staging/Dev environment
            Log::info('Pos Laju: Using TEST/DEV environment');
        } else {
            $this->apiUrl = 'https://posapi.pos.com.my'; // Production environment
        }
    }

    /**
     * Get OAuth2 access token with automatic refresh
     */
    protected function getAccessToken()
    {
        if (!$this->settings || !$this->settings->hasOAuthCredentials()) {
            Log::error('Pos Laju OAuth credentials not configured', [
                'has_settings' => !is_null($this->settings),
                'user_id' => $this->settings->user_id ?? null,
            ]);
            return null;
        }

        // Check if we have a valid token in database
        if ($this->settings->hasValidToken()) {
            Log::info('Pos Laju: Using cached OAuth token', [
                'user_id' => $this->settings->user_id,
                'expires_at' => $this->settings->token_expires_at,
            ]);
            return $this->settings->access_token;
        }

        // Need to get a new token
        try {
            $tokenUrl = $this->apiUrl . '/oauth2/token';

            Log::info('Pos Laju: Requesting new OAuth token', [
                'url' => $tokenUrl,
                'client_id' => substr($this->settings->client_id, 0, 10) . '...',
                'test_mode' => $this->settings->test_mode ?? false,
            ]);

            $response = Http::timeout(30)
                ->withHeaders([
                    'Accept' => 'application/json',
                    'Content-Type' => 'application/x-www-form-urlencoded',
                ])
                ->asForm()
                ->post($tokenUrl, [
                    'client_id' => $this->settings->client_id,
                    'client_secret' => $this->settings->client_secret,
                    'grant_type' => 'client_credentials',
                ]);

            Log::info('Pos Laju OAuth response received', [
                'status' => $response->status(),
                'successful' => $response->successful(),
            ]);

            if ($response->successful()) {
                $data = $response->json();
                $accessToken = $data['access_token'] ?? null;
                $expiresIn = $data['expires_in'] ?? 3600; // Default 1 hour

                if ($accessToken) {
                    // Save token to database
                    $this->settings->update([
                        'access_token' => $accessToken,
                        'token_expires_at' => now()->addSeconds($expiresIn - 300), // Refresh 5 min before expiry
                    ]);

                    Log::info('Pos Laju OAuth token generated successfully', [
                        'user_id' => $this->settings->user_id,
                        'expires_at' => $this->settings->token_expires_at,
                    ]);

                    return $accessToken;
                }
            }

            // Log detailed error
            Log::error('Pos Laju OAuth token request failed', [
                'status' => $response->status(),
                'headers' => $response->headers(),
                'body' => $response->body(),
                'url' => $tokenUrl,
            ]);

            return null;

        } catch (Exception $e) {
            Log::error('Pos Laju OAuth exception', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'user_id' => $this->settings->user_id ?? null,
                'url' => $this->apiUrl ?? 'unknown',
            ]);
            return null;
        }
    }

    /**
     * Generate AWB (Air Waybill) consignment number
     *
     * @param array $order - Order details
     * @return array ['success' => bool, 'tracking_number' => string, 'message' => string, 'data' => array]
     */
    public function generateAWB($order)
    {
        // TEST MODE: Generate fake tracking number
        if ($this->settings && $this->settings->test_mode) {
            $trackingNumber = 'TEST' . date('ymd') . str_pad($order->id, 6, '0', STR_PAD_LEFT) . 'MY';

            Log::info('Pos Laju TEST MODE: Generated fake AWB', [
                'order_id' => $order->id,
                'tracking_number' => $trackingNumber
            ]);

            return [
                'success' => true,
                'tracking_number' => $trackingNumber,
                'message' => 'Test AWB generated (Test Mode enabled)',
                'data' => [
                    'test_mode' => true,
                    'connote_no' => $trackingNumber,
                    'generated_at' => now()->toIso8601String()
                ]
            ];
        }

        // Validate order data first
        $validation = PoslajuValidator::validateOrder($order);

        if (!$validation['valid']) {
            Log::warning('Pos Laju AWB validation failed', [
                'order_id' => $order->id,
                'errors' => $validation['errors']
            ]);

            return [
                'success' => false,
                'message' => 'Validation failed: ' . implode('; ', $validation['errors']),
                'tracking_number' => null,
                'data' => ['validation_errors' => $validation['errors']]
            ];
        }

        $token = $this->getAccessToken();

        if (!$token) {
            return [
                'success' => false,
                'message' => 'Failed to authenticate with Pos Laju API',
                'tracking_number' => null,
                'data' => null
            ];
        }

        try {
            // Prepare consignment data with validated/corrected information
            $consignmentData = $this->prepareConsignmentData($order, $validation['corrected']);

            // Log the request for debugging
            Log::info('Pos Laju AWB Request', [
                'url' => $this->apiUrl . '/order/create',
                'data' => $consignmentData,
            ]);

            // Call Pos Laju API to create order
            $response = Http::withToken($token)
                ->withHeaders([
                    'Content-Type' => 'application/json',
                    'Accept' => 'application/json',
                ])
                ->post($this->apiUrl . '/order/create', $consignmentData);

            // Log the response for debugging
            Log::info('Pos Laju AWB Response', [
                'status' => $response->status(),
                'body' => $response->body(),
            ]);

            if ($response->successful()) {
                $data = $response->json();

                // Pos Laju API v2 returns Tracking_Number (capitalized)
                $trackingNumber = $data['Tracking_Number']
                    ?? $data['tracking_number']
                    ?? $data['connote_no']
                    ?? $data['consignment_no']
                    ?? $data['data']['Tracking_Number']
                    ?? null;

                if ($trackingNumber) {
                    Log::info('Pos Laju AWB generated successfully', [
                        'tracking_number' => $trackingNumber,
                        'transaction_id' => $data['Transaction_Id'] ?? null,
                    ]);

                    return [
                        'success' => true,
                        'tracking_number' => $trackingNumber,
                        'message' => 'AWB generated successfully',
                        'data' => $data
                    ];
                }

                return [
                    'success' => false,
                    'message' => 'Tracking number not found in response',
                    'tracking_number' => null,
                    'data' => $data
                ];
            }

            Log::error('Pos Laju AWB generation failed', [
                'status' => $response->status(),
                'body' => $response->body()
            ]);

            return [
                'success' => false,
                'message' => 'Failed to generate AWB: ' . $response->body(),
                'tracking_number' => null,
                'data' => $response->json()
            ];

        } catch (Exception $e) {
            Log::error('Pos Laju AWB generation exception', [
                'error' => $e->getMessage(),
                'order_id' => $order->id ?? null
            ]);

            return [
                'success' => false,
                'message' => 'Exception: ' . $e->getMessage(),
                'tracking_number' => null,
                'data' => null
            ];
        }
    }

    /**
     * Prepare consignment data for Pos Laju API
     */
    protected function prepareConsignmentData($order, $correctedData = [])
    {
        // Get shipping address (use shipping if available, otherwise billing)
        $shipping = $order->shipping ?? $order->billing;
        $billing = $order->billing;

        // Use corrected data if available, otherwise use original
        // Support both 'name' field (sales pages) and 'first_name'+'last_name' (checkout/WooCommerce)
        if (!empty($correctedData['name'])) {
            $receiverName = \App\Helpers\PoslajuValidator::sanitizeText($correctedData['name']);
        } else {
            $rawName = ($shipping['name'] ?? $billing['name'] ?? '') ?:
                       (($shipping['first_name'] ?? '') . ' ' . ($shipping['last_name'] ?? ''));
            $receiverName = \App\Helpers\PoslajuValidator::sanitizeText($rawName);
        }

        $receiverPhone = $correctedData['phone'] ?? ($shipping['phone'] ?? $billing['phone'] ?? '');
        $receiverEmail = $correctedData['email'] ?? ($billing['email'] ?? config('mail.from.address'));
        $receiverState = \App\Helpers\PoslajuValidator::sanitizeText($correctedData['state'] ?? ($shipping['state'] ?? $billing['state'] ?? ''));
        $receiverCity = \App\Helpers\PoslajuValidator::sanitizeText($correctedData['city'] ?? ($shipping['city'] ?? $billing['city'] ?? ''));

        // Calculate total weight from order items or use default
        $totalWeight = $this->settings->default_weight ?? 0.3;

        // Build item details array with proper structure
        $itemDetails = [];
        $itemWeight = ($totalWeight / max(1, count($order->line_items ?? []))); // Distribute weight evenly

        // Check if order has line_items (from WooCommerce/Webhooks)
        if ($order->line_items && is_array($order->line_items) && count($order->line_items) > 0) {
            foreach ($order->line_items as $item) {
                $itemDetails[] = [
                    'length' => floatval($this->settings->default_dimension_l ?? 1),
                    'width' => floatval($this->settings->default_dimension_w ?? 1),
                    'height' => floatval($this->settings->default_dimension_h ?? 1),
                    'weight' => floatval($itemWeight),
                    'weight_unit' => 'kg',
                    'description' => \App\Helpers\PoslajuValidator::sanitizeText($item['name'] ?? ($item['product_name'] ?? 'Product')),
                ];
            }
        } else {
            // Fallback item if no items found
            $itemDetails[] = [
                'length' => floatval($this->settings->default_dimension_l ?? 1),
                'width' => floatval($this->settings->default_dimension_w ?? 1),
                'height' => floatval($this->settings->default_dimension_h ?? 1),
                'weight' => floatval($totalWeight),
                'weight_unit' => 'kg',
                'description' => \App\Helpers\PoslajuValidator::sanitizeText('Order #' . $order->order_number),
            ];
        }

        // Convert Item_Type to STRING value (API expects string)
        // 0 = Document, 1 = Merchandise, 2 = Parcel
        $itemTypeMap = [
            'Document' => '0',
            'Merchandise' => '1',
            'Parcel' => '2',
        ];
        $itemType = $itemTypeMap[$this->settings->item_type ?? 'Parcel'] ?? '2';

        // Get receiver address parts (support both 'address_1' and 'address' formats)
        // Use corrected address from validator first, then fallback to raw data
        $receiverAddressLine1 = $correctedData['address'] ??
                                $shipping['address_1'] ?? $shipping['address'] ??
                                $billing['address_1'] ?? $billing['address'] ?? '';

        // Sanitize and ensure not empty
        $receiverAddressLine1 = \App\Helpers\PoslajuValidator::sanitizeText($receiverAddressLine1);

        // Address line 2 (optional)
        $receiverAddressLine2 = \App\Helpers\PoslajuValidator::sanitizeText($shipping['address_2'] ?? $billing['address_2'] ?? '');

        // Build base request data
        $requestData = [
            // Required: Account Information
            'Account_Number' => $this->settings->account_number ?? config('poslaju.credentials.account_number'),

            // Required: API Configuration Fields
            // Product_Code must be one of: 80000000, 80001158, 80001159, 80001150, 80001502, 80000001, 80001120, 80001121, 80001598, 80001610
            'Product_Code' => $this->settings->poslaju_account_id ?? config('poslaju.credentials.poslaju_account_id', '80000000'),
            'Item_Type' => $itemType, // STRING: "0"=Document, "1"=Merchandise, "2"=Parcel
            'Service_Level' => $this->settings->service_level ?? 'Standard',
            'Order_Validity' => intval($this->settings->order_validity ?? 7),
            'Webhook_IsRequired' => false, // Set to false - we don't have webhook endpoint configured

            // Required: Reference (must be object with merchant_order_number)
            'Reference' => [
                'merchant_order_number' => $order->global_order_id ?? $order->order_number,
                'merchant_reference_number' => $order->global_order_id ?? $order->order_number,
            ],

            // Required: Pickup information
            'Pickup' => [
                'is_required' => false, // Set to true if pickup is needed
            ],

            // Sender information (lowercase as per API docs)
            'Sender' => [
                'name' => \App\Helpers\PoslajuValidator::sanitizeText($this->settings->sender_name ?? config('poslaju.sender.name')),
                'phone_number' => $this->settings->sender_phone ?? config('poslaju.sender.phone'),
                'email' => config('mail.from.address'),
                'address' => [
                    'address1' => \App\Helpers\PoslajuValidator::sanitizeText($this->settings->sender_address ?? config('poslaju.sender.address')),
                    'address2' => '',
                    'area' => \App\Helpers\PoslajuValidator::sanitizeText($this->settings->sender_city ?? config('poslaju.sender.city')),
                    'city' => \App\Helpers\PoslajuValidator::sanitizeText($this->settings->sender_city ?? config('poslaju.sender.city')),
                    'state' => \App\Helpers\PoslajuValidator::sanitizeText($this->settings->sender_state ?? config('poslaju.sender.state')),
                    'address_type' => 'Office',
                    'country' => 'MY',
                    'postcode' => $this->settings->sender_postcode ?? config('poslaju.sender.postcode'),
                ],
            ],

            // Required: Receiver information (lowercase as per API docs)
            'Receiver' => [
                'name' => $receiverName ?: 'Customer',
                'phone_number' => $receiverPhone ?: '',
                'email' => $receiverEmail,
                'address' => [
                    'address1' => $receiverAddressLine1,
                    'address2' => $receiverAddressLine2,
                    'area' => $receiverCity ?: '',
                    'city' => $receiverCity ?: '',
                    'state' => $receiverState ?: '',
                    'address_type' => 'Home',
                    'country' => 'MY',
                    'postcode' => $shipping['postcode'] ?? $billing['postcode'] ?? '',
                ],
            ],

            // Required: Item Details (lowercase!)
            'Item_Details' => $itemDetails,

            // Required: Total Weight
            'Total_Weight' => floatval($totalWeight),

            // Optional: Added Services (COD, Insurance, etc.)
            'Added_Services' => $order->isCOD() ? [
                [
                    'addedCode' => 'COD',
                    'amount' => strval(floatval($order->total)),
                ],
            ] : [],
        ];

        // Add Subscription_Code only if provided (optional field)
        // When omitted, Pos Laju will auto-generate tracking prefix based on service type
        if (!empty($this->settings->subscription_code)) {
            $requestData['Subscription_Code'] = $this->settings->subscription_code;
        }

        return $requestData;
    }

    /**
     * Track shipment by tracking number
     */
    public function trackShipment($trackingNumber)
    {
        $token = $this->getAccessToken();

        if (!$token) {
            return [
                'success' => false,
                'message' => 'Failed to authenticate with Pos Laju API',
                'data' => null
            ];
        }

        try {
            $response = Http::withToken($token)
                ->get($this->apiUrl . '/track/' . $trackingNumber);

            if ($response->successful()) {
                return [
                    'success' => true,
                    'message' => 'Tracking information retrieved',
                    'data' => $response->json()
                ];
            }

            return [
                'success' => false,
                'message' => 'Failed to track shipment',
                'data' => $response->json()
            ];

        } catch (Exception $e) {
            Log::error('Pos Laju tracking exception', [
                'error' => $e->getMessage(),
                'tracking_number' => $trackingNumber
            ]);

            return [
                'success' => false,
                'message' => 'Exception: ' . $e->getMessage(),
                'data' => null
            ];
        }
    }

    /**
     * Get Pos Laju tracking URL
     */
    public function getTrackingUrl($trackingNumber)
    {
        return 'https://tracking.pos.com.my/tracking/' . $trackingNumber;
    }
}
