<?php

namespace App\Services;

use App\Models\Order;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;

class CourierService
{
    protected string $apiKey;
    protected string $baseUrl;

    public function __construct()
    {
        $this->apiKey = config('courier.api_key');
        $this->baseUrl = config('courier.api_base_url', 'https://api.shiplogic.com/api');
    }

    /**
     * Create shipment with full validation and database updates
     * 
     * @param Order $order
     * @return array{waybill_id: string, tracking_number: string, sticker_path: ?string, waybill_path: ?string}
     * @throws \Exception
     */
    public function createShipmentForOrder(Order $order): array
    {
        Log::info('Creating shipment for order', ['order_uuid' => $order->uuid]);

        // Guard 1: Validate packing
        if (! $this->validatePacking($order)) {
            throw new \Exception('Order not yet packed with valid dimensions');
        }

        // Guard 2: Validate payment/approval
        if (! $this->validatePayment($order)) {
            throw new \Exception($order->is_custom_order ?
                'Custom order requires proof approved and balance paid' :
                'Standard order must be fully paid'
            );
        }

        // Guard 3: Validate order status
        if ($order->status !== 'ready_to_ship') {
            throw new \Exception('Order must be in Ready to Ship state');
        }

        // Guard 4: Prevent duplicates
        if ($order->courier_waybill_id) {
            throw new \Exception('Shipment already exists for this order');
        }

        try {
            // Call API to create shipment
            $shipmentData = $this->callCreateShipmentApi(
                $order->id,
                $order->packing_width,
                $order->packing_length,
                $order->packing_weight,
            );

            // Save shipment details to database
            $order->update([
                'courier_waybill_id' => $shipmentData['waybill_id'],
                'courier_tracking_number' => $shipmentData['tracking_number'],
                'courier_status' => 'awaiting_collection',
                'status' => 'awaiting_collection',
            ]);

            Log::info('Shipment created successfully', [
                'order_uuid' => $order->uuid,
                'waybill_id' => $shipmentData['waybill_id'],
            ]);

            // Fetch shipping documents
            $stickerPath = $this->fetchSticker($shipmentData['shipment_id'], $order->id);
            $waybillPath = $this->fetchWaybill($shipmentData['shipment_id'], $order->id);

            return [
                'waybill_id' => $shipmentData['waybill_id'],
                'tracking_number' => $shipmentData['tracking_number'],
                'sticker_path' => $stickerPath,
                'waybill_path' => $waybillPath,
            ];
        } catch (\Exception $e) {
            Log::error('Failed to create shipment', [
                'order_uuid' => $order->uuid,
                'error' => $e->getMessage(),
            ]);

            throw $e;
        }
    }

    /**
     * Create a shipment with Shiplogic API
     * 
     * @param string $orderId
     * @param float $width Width in cm
     * @param float $length Length in cm
     * @param float $weight Weight in kg
     * @return array{shipment_id: string, waybill_id: string, tracking_number: string}
     * @throws \Exception
     */
    private function callCreateShipmentApi(string $orderId, float $width, float $length, float $weight): array
    {
        if (! $this->isConfigured()) {
            throw new \Exception('Courier API not configured');
        }

        if ($width <= 0 || $length <= 0 || $weight <= 0) {
            throw new \Exception('Invalid dimensions or weight: all must be greater than 0');
        }

        try {
            // Build shipment payload for Shiplogic
            $payload = [
                'parcel' => [
                    'weight' => $weight,
                    'height' => 10, // TODO: Update when height is captured separately
                    'width' => $width,
                    'length' => $length,
                ],
                'destination' => [
                    // TODO: Get from order's shipping address
                ],
                'reference' => $orderId,
            ];

            $response = Http::withHeaders([
                'Authorization' => "Bearer {$this->apiKey}",
            ])->post("{$this->baseUrl}/shipments", $payload);

            if (! $response->successful()) {
                $errorMessage = $response->json('error.message', 'Unknown error');
                throw new \Exception("Courier API error: {$errorMessage}");
            }

            $data = $response->json();

            return [
                'shipment_id' => $data['id'] ?? null,
                'waybill_id' => $data['waybill_number'] ?? null,
                'tracking_number' => $data['tracking_number'] ?? null,
            ];
        } catch (\Exception $e) {
            Log::error('Failed to call courier API', [
                'order_id' => $orderId,
                'error' => $e->getMessage(),
            ]);

            throw $e;
        }
    }

    /**
     * Validate packing gate: order must be packed with dimensions
     */
    private function validatePacking(Order $order): bool
    {
        $valid = $order->packing_completed_at !== null &&
            $order->packing_width > 0 &&
            $order->packing_length > 0 &&
            $order->packing_weight > 0;

        if (! $valid) {
            Log::warning('Packing validation failed', [
                'order_uuid' => $order->uuid,
                'packing_completed_at' => $order->packing_completed_at,
                'width' => $order->packing_width,
                'length' => $order->packing_length,
                'weight' => $order->packing_weight,
            ]);
        }

        return $valid;
    }

    /**
     * Validate payment and approval gate
     */
    private function validatePayment(Order $order): bool
    {
        // Standard orders: must be fully paid
        if ($order->is_custom_order === false) {
            $valid = $order->payment_status === 'paid';
        } else {
            // Custom orders: proof must be approved and balance must be paid
            // TODO: Add proof_approved and balance_status fields to CustomOrder model
            $valid = true; // Placeholder
        }

        if (! $valid) {
            Log::warning('Payment validation failed', [
                'order_uuid' => $order->uuid,
                'is_custom_order' => $order->is_custom_order,
                'payment_status' => $order->payment_status,
            ]);
        }

        return $valid;
    }

    /**
     * Fetch shipping label/sticker PDF from Shiplogic
     */
    public function fetchSticker(string $shipmentId, string $orderId): ?string
    {
        if (! $this->isConfigured()) {
            return null;
        }

        try {
            $response = Http::withHeaders([
                'Authorization' => "Bearer {$this->apiKey}",
            ])->get("{$this->baseUrl}/shipments/{$shipmentId}/sticker");

            if ($response->successful()) {
                $path = "shipments/{$orderId}/sticker.pdf";
                Storage::disk('public')->put($path, $response->body());

                return $path;
            }

            Log::warning('Failed to fetch sticker from courier', ['shipment_id' => $shipmentId]);

            return null;
        } catch (\Exception $e) {
            Log::error('Exception fetching sticker', ['error' => $e->getMessage()]);

            return null;
        }
    }

    /**
     * Fetch waybill PDF from Shiplogic
     */
    public function fetchWaybill(string $shipmentId, string $orderId): ?string
    {
        if (! $this->isConfigured()) {
            return null;
        }

        try {
            $response = Http::withHeaders([
                'Authorization' => "Bearer {$this->apiKey}",
            ])->get("{$this->baseUrl}/shipments/{$shipmentId}/label");

            if ($response->successful()) {
                $path = "shipments/{$orderId}/waybill.pdf";
                Storage::disk('public')->put($path, $response->body());

                return $path;
            }

            Log::warning('Failed to fetch waybill from courier', ['shipment_id' => $shipmentId]);

            return null;
        } catch (\Exception $e) {
            Log::error('Exception fetching waybill', ['error' => $e->getMessage()]);

            return null;
        }
    }

    /**
     * Check if courier is configured
     */
    protected function isConfigured(): bool
    {
        return ! empty($this->apiKey);
    }
}
