<?php

namespace App\Services;

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

/**
 * Royal Mail Click & Drop API integration.
 *
 * When you receive API credentials, fill in admin Settings → Royal Mail:
 *   - Royal Mail API Key  (Click & Drop → Settings → API)
 *   - OBA Account Number (your Online Business Account number)
 *
 * Docs: https://developer.royalmail.net/node/2333
 *
 * In test mode (no credentials): returns mock tracking numbers so the
 * rest of the order flow can be tested end-to-end.
 */
class RoyalMailService
{
    private const API_URL = 'https://api.royalmail.net/shipping/v3';

    private ?string $apiKey;
    private ?string $accountNumber;

    public function __construct()
    {
        $settings = DB::table('store_settings')->pluck('value', 'key');
        $this->apiKey        = $settings->get('royalmail_api_key') ?: null;
        $this->accountNumber = $settings->get('royalmail_account_number') ?: null;
    }

    public function isConfigured(): bool
    {
        return !empty($this->apiKey) && !empty($this->accountNumber);
    }

    /**
     * Create a shipment and return tracking number + label URL.
     *
     * @param  Order  $order
     * @param  string $serviceCode  e.g. 'RM2630' = Tracked 48, 'RM2631' = Tracked 24, 'RM2632' = Special Delivery
     * @param  int    $weightGrams
     * @return array{ tracking_number: string, label_url: string|null, test_mode: bool }
     */
    public function createShipment(Order $order, string $serviceCode, int $weightGrams): array
    {
        if (!$this->isConfigured()) {
            return $this->testModeShipment($order);
        }

        $addr = $order->shippingAddress;

        $payload = [
            'shipper'    => ['accountNumber' => $this->accountNumber],
            'service'    => [
                'format'      => 'P', // Parcel
                'occurrence'  => '1',
                'serviceCode' => $serviceCode,
            ],
            'shipmentDate' => now()->format('Y-m-d'),
            'items'        => [[
                'itemId'      => $order->order_number,
                'weight'      => ['unitOfMeasure' => 'g', 'value' => $weightGrams],
                'recipient'   => [
                    'name'    => trim(($addr->first_name ?? '') . ' ' . ($addr->last_name ?? '')),
                    'address' => [
                        'line1'      => $addr->address_line_1 ?? '',
                        'line2'      => $addr->address_line_2 ?? '',
                        'city'       => $addr->city ?? '',
                        'county'     => $addr->county ?? '',
                        'postcode'   => $addr->postcode ?? '',
                        'countryCode'=> strtoupper($addr->country ?? 'GB'),
                    ],
                    'phone'   => $addr->phone ?? '',
                    'email'   => $order->user?->email ?? $order->guest_email ?? '',
                ],
            ]],
        ];

        $response = Http::withHeaders([
                'Authorization' => "Bearer {$this->apiKey}",
                'Accept'        => 'application/json',
                'Content-Type'  => 'application/json',
                'X-IBM-Client-Id' => $this->apiKey, // Click & Drop uses this header
            ])
            ->post(self::API_URL . '/shipments', $payload);

        if (!$response->successful()) {
            Log::error('RoyalMail: createShipment failed', [
                'status' => $response->status(),
                'body'   => $response->body(),
            ]);
            throw new \RuntimeException('Royal Mail API error: ' . ($response->json('message') ?? $response->body()));
        }

        $data = $response->json();

        // TODO: confirm exact field names once you have API access
        $trackingNumber = $data['items'][0]['trackingNumber']
            ?? $data['trackingNumber']
            ?? $data['items'][0]['barcode']
            ?? null;

        $labelUrl = $data['items'][0]['label']
            ?? $data['label']
            ?? null;

        if (!$trackingNumber) {
            throw new \RuntimeException('Royal Mail did not return a tracking number.');
        }

        return [
            'tracking_number' => $trackingNumber,
            'label_url'       => $labelUrl,
            'test_mode'       => false,
        ];
    }

    /**
     * Fetch a label PDF URL for an existing shipment.
     */
    public function getLabel(string $trackingNumber): ?string
    {
        if (!$this->isConfigured()) return null;

        $response = Http::withHeaders([
                'Authorization'   => "Bearer {$this->apiKey}",
                'X-IBM-Client-Id' => $this->apiKey,
            ])
            ->get(self::API_URL . '/shipments/' . $trackingNumber . '/label');

        if (!$response->successful()) return null;

        return $response->json('labelUrl') ?? $response->json('url');
    }

    // ── Test mode ─────────────────────────────────────────────────────────────

    private function testModeShipment(Order $order): array
    {
        // Generate a realistic-looking test tracking number
        $tracking = 'TT' . strtoupper(substr(md5($order->order_number), 0, 8)) . 'GB';

        return [
            'tracking_number' => $tracking,
            'label_url'       => null,
            'test_mode'       => true,
        ];
    }

    // ── Service codes ─────────────────────────────────────────────────────────

    public static function services(): array
    {
        return [
            'RM2630' => ['name' => 'Royal Mail Tracked 48', 'description' => '2–3 working days'],
            'RM2631' => ['name' => 'Royal Mail Tracked 24', 'description' => '1–2 working days'],
            'RM2632' => ['name' => 'Royal Mail Special Delivery', 'description' => 'Guaranteed next day before 1pm'],
            'RM2633' => ['name' => 'Royal Mail Tracked 48 Large Letter', 'description' => '2–3 working days'],
            'RM2634' => ['name' => 'Royal Mail Tracked 24 Large Letter', 'description' => '1–2 working days'],
        ];
    }
}
