<?php

namespace App\Services\Carriers;

use App\Models\Order;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

class ExpressBeesCarrier implements CarrierInterface
{
    protected Client $client;
    protected array $config;
    protected ?string $token = null;

    public function __construct(array $config)
    {
        $this->config = $config;
        $this->client = new Client([
            'base_uri' => $config['api_url'] ?? 'https://ship.xpressbees.com',
            'timeout' => 30,
            'verify' => public_path('cacert.pem'),
        ]);
    }

    public function createShipment(Order $order, array $formData = []): array
    {
        try {
            $token = $this->getToken();
            $address = $order->address_snapshot;
            $codAmount = $formData['cod_amount'] ?? 0;

            $data = [
                'id' => (string) '#' . $order->id,
                'payment_method' => $formData['payment_mode'] ?? ($codAmount > 0 ? 'COD' : 'prepaid'),
                'consigner_name' => $formData['consigner_name'] ?? (config('services.xpressbees.consigner_name') ?? 'Consigner'),
                'consigner_phone' => $formData['consigner_phone'] ?? (config('services.xpressbees.consigner_phone') ?? ''),
                'consigner_pincode' => $formData['consigner_pincode'] ?? (config('services.xpressbees.consigner_pincode') ?? ''),
                'consigner_city' => $formData['consigner_city'] ?? (config('services.xpressbees.consigner_city') ?? ''),
                'consigner_state' => $formData['consigner_state'] ?? (config('services.xpressbees.consigner_state') ?? ''),
                'consigner_address' => $formData['consigner_address'] ?? (config('services.xpressbees.consigner_address') ?? ''),
                'consigner_gst_number' => $formData['consigner_gst_number'] ?? (config('services.xpressbees.gstin') ?? ''),
                'consignee_name' => $address['name'],
                'consignee_phone' => $address['mobile'],
                'consignee_pincode' => $address['pin'],
                'consignee_city' => $address['city'],
                'consignee_state' => $address['state'],
                'consignee_address' => $address['line1'] . ' ' . ($address['line2'] ?? ''),
                'consignee_gst_number' => isset($order->user->gst_number) ? $order->user->gst_number : ($address['gst_number'] ?? ''),
                'products' => $this->mapProducts($order),
                'shipping_charges' => $order->shipping_total,
                'discount' => $order->discount_total,
                'invoice' => [
                    [
                        'invoice_number' => $formData['invoice_number'] ?? ('INV-' . $order->id),
                        'invoice_date' => $formData['invoice_date'] ?? now()->format('Y-m-d'),
                    ],
                ],
                'weight' => (string) ($formData['weight'] ?? 55),
                'length' => (string) ($formData['length'] ?? 10),
                'breadth' => (string) ($formData['width'] ?? 5),
                'height' => (string) ($formData['height'] ?? 3),
                'courier_id' => $formData['courier_id'] ?? ($this->config['courier_id'] ?? ''),
                'pickup_location' => $formData['pickup_location'] ?? (config('services.xpressbees.pickup_location') ?? 'franchise'),
                'order_amount' => $codAmount > 0 ? $codAmount : $order->total_payable,
                'collectable_amount' => $codAmount > 0 ? $codAmount : 0,
            ];

            $response = $this->client->post('/api/franchise/shipments', $this->withAuth($token, $data));

            $result = json_decode($response->getBody()->getContents(), true);

            if (isset($result['data']['awb_number'])) {
                $awb = $result['data']['awb_number'];

                Log::info('XpressBees shipment created', [
                    'order_id' => $order->id,
                    'awb' => $awb,
                ]);

                return [
                    'tracking_id' => $awb,
                    'raw_response' => $result,
                    'metadata' => $result['data'] ?? [],
                ];
            }

            Log::error('XpressBees shipment creation failed', [
                'order_id' => $order->id,
                'response' => $result,
            ]);

            throw new \Exception('Failed to create XpressBees shipment: ' . ($result['message'] ?? 'Unknown error'));
        } catch (\Exception $e) {
            Log::error('XpressBees shipment creation exception', [
                'order_id' => $order->id,
                'error' => $e->getMessage(),
            ]);

            throw $e;
        }
    }

    public function generateLabel(string $trackingId): ?string
    {
        try {
            $apiUrl = $this->config['api_url'] ?? 'https://ship.xpressbees.com';
            $labelUrl = $apiUrl . '/api/franchise/shipments/label?awb=' . $trackingId;

            Log::info('XpressBees label generated', [
                'awb' => $trackingId,
                'url' => $labelUrl,
            ]);

            return $labelUrl;
        } catch (\Exception $e) {
            Log::error('XpressBees label generation failed', [
                'awb' => $trackingId,
                'error' => $e->getMessage(),
            ]);

            return null;
        }
    }

    public function track(string $trackingId): ?array
    {
        try {
            $token = $this->getToken();
            $response = $this->client->post('/api/franchise/shipments/track_shipment', $this->withAuth($token, [
                'awb_number' => $trackingId,
            ]));

            $result = json_decode($response->getBody()->getContents(), true);

            return $result['data'] ?? $result ?? null;
        } catch (\Exception $e) {
            Log::error('XpressBees tracking failed', [
                'awb' => $trackingId,
                'error' => $e->getMessage(),
            ]);

            return null;
        }
    }

    public function validateConfig(array $config): bool
    {
        return !empty($config['email']) && !empty($config['password']);
    }

    /**
     * Check delivery availability for a given pincode
     *
     * @param string $pincode
     * @return array Returns array with 'available' (bool) and 'message' (string)
     */
    public function checkDeliveryAvailability(string $pincode): array
    {
        // XpressBees availability check not implemented yet
        return [
            'available' => false,
            'message' => 'Delivery availability check not available for XpressBees',
        ];
    }

    protected function getProductsDescription(Order $order): string
    {
        $items = $order->items->map(function ($item) {
            return $item->name . ' (x' . $item->qty . ')';
        })->take(3)->toArray();

        return implode(', ', $items);
    }

    protected function mapProducts(Order $order): array
    {
        return $order->items->map(function ($item) {
            return [
                'product_name' => $item->name,
                'product_qty' => (string) $item->qty,
                'product_price' => (string) ($item->line_total ?? 0),
            ];
        })->values()->toArray();
    }

    protected function getToken(): string
    {
        if ($this->token) {
            return $this->token;
        }

        $cacheKey = 'expressbees_token_' . md5($this->config['email'] ?? '');

        return $this->token = Cache::remember($cacheKey, now()->addMinutes(50), function () {
            if (empty($this->config['email']) || empty($this->config['password'])) {
                throw new \RuntimeException('XpressBees credentials missing');
            }

            $response = $this->client->post('/api/users/franchise_user_login', [
                'headers' => [
                    'Content-Type' => 'application/json',
                ],
                'json' => [
                    'username' => $this->config['email'],
                    'password' => $this->config['password'],
                ],
            ]);

            $body = json_decode($response->getBody()->getContents(), true);
            $token = $body['token'] ?? ($body['data'] ?? null);

            if (!$token) {
                throw new \RuntimeException('XpressBees login failed');
            }

            return $token;
        });
    }

    protected function withAuth(string $token, array $json = []): array
    {
        return [
            'headers' => [
                'Authorization' => 'Bearer ' . $token,
                'Content-Type' => 'application/json',
            ],
            'json' => $json,
        ];
    }
}

