<?php

namespace App\Services\Hotspot;

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

class VoucherService
{
    /**
     * Generate voucher on Mikrotik, save into DB and update order.
     * This should ONLY be called when payment is CONFIRMED.
     */
    public function generateForOrder(Order $order): string
    {
        // Avoid double-generation
        if ($order->voucher_code) {
            Log::info('VoucherService: voucher already exists, skipping generation', [
                'order_id'      => $order->id,
                'voucher_code'  => $order->voucher_code,
                'status'        => $order->status,
            ]);
            return $order->voucher_code;
        }

        /** @var Router|null $router */
        $router = $order->router;
        /** @var Plan|null $plan */
        $plan   = $order->plan;

        Log::info('VoucherService: DEBUG_ORDER', [
            'order_id'      => $order->id,
            'router_id'     => $order->router_id,
            'plan_id'       => $order->plan_id,
            'phone'         => $order->phone,
            'amount'        => $order->amount,
            'router_exists' => (bool) $router,
            'plan_exists'   => (bool) $plan,
        ]);

        if (! $router) {
            Log::error('VoucherService: NO_ROUTER', [
                'order_id'  => $order->id,
                'router_id' => $order->router_id,
            ]);
            throw new RuntimeException('Router missing on order ID ' . $order->id);
        }

        if (! $plan) {
            Log::error('VoucherService: NO_PLAN', [
                'order_id' => $order->id,
                'plan_id'  => $order->plan_id,
            ]);
            throw new RuntimeException('Plan missing on order ID ' . $order->id);
        }

        // -------- 1. Build voucher data --------
        $code   = (string) random_int(10000000, 99999999);   // 8 digits
        $hours  = (int) ($plan->validity_hours ?? 1);        // fallback 1h
        $totalMinutes = max($hours * 60, 30);                // at least 30 mins
        $h = floor($totalMinutes / 60);
        $m = $totalMinutes % 60;
        $limitUptime = sprintf('%d:%02d:00', $h, $m);

        $profile = $plan->profile ?: 'default';

        Log::info('VoucherService: generating voucher', [
            'order_id'      => $order->id,
            'router_id'     => $router->id,
            'plan_id'       => $plan->id,
            'code'          => $code,
            'profile'       => $profile,
            'limit_uptime'  => $limitUptime,
            'total_minutes' => $totalMinutes,
        ]);

        // -------- 2. Push to MikroTik (RouterosAPI) --------
        $this->createHotspotUserOnMikrotik(
            $router,
            $code,
            $code,
            $profile,
            $limitUptime
        );

        // -------- 3. Save voucher + update order (one transaction) --------
        $expiresAt = now()->addMinutes($totalMinutes);

        Log::info('VoucherService: DB_BEFORE_INSERT', [
            'order_id'      => $order->id,
            'router_id'     => $router->id,
            'plan_id'       => $plan->id,
            'code'          => $code,
            'profile'       => $profile,
            'total_minutes' => $totalMinutes,
            'expires_at'    => $expiresAt,
        ]);

        DB::transaction(function () use ($order, $router, $plan, $code, $profile, $totalMinutes, $expiresAt) {
            DB::table('vouchers')->insert([
                'router_id'        => $router->id,
                'order_id'         => $order->id,
                'code'             => $code,
                'phone'            => $order->phone,
                'profile'          => $profile,
                'amount'           => $order->amount,
                'currency'         => $order->currency,
                'status'           => 'unused',
                'time_limit'       => $totalMinutes,
                'failure_notified' => 0,
                'created_at'       => now(),
                'updated_at'       => now(),
                'expires_at'       => $expiresAt,
            ]);

            $order->voucher_code = $code;
            $order->status       = 'success';

            $meta = $order->meta ?? [];
            $meta['voucher_generated_at'] = now()->toDateTimeString();
            $order->meta = $meta;

            $order->save();
        });

        // -------- 4. Send SMS via Beem --------
        $this->sendSuccessSms($order, $plan, $code);

        Log::info('VoucherService: voucher generated successfully', [
            'order_id' => $order->id,
            'code'     => $code,
        ]);

        return $code;
    }

    /**
     * Connect to Mikrotik & create hotspot user
     * using the classic routeros_api.class.php (same as your old system).
     */
    protected function createHotspotUserOnMikrotik(
        Router $router,
        string $username,
        string $password,
        string $profile,
        string $limitUptime
    ): void {
        // Include classic MikroTik API client
        $apiPath = base_path('libs/routeros_api.class.php');
        if (!file_exists($apiPath)) {
            Log::error('RouterosAPI file not found', ['path' => $apiPath]);
            throw new RuntimeException('RouterosAPI library not found.');
        }
        require_once $apiPath;

        $host    = $router->host ?? $router->ip ?? null;
        $apiPort = $router->api_port ?: 8728;
        $user    = $router->username;
        $pass    = $router->password;

        if (! $host || ! $user || ! $pass) {
            Log::error('VoucherService: missing MikroTik credentials', [
                'router_id' => $router->id,
                'host'      => $host,
                'user'      => $user,
            ]);
            throw new RuntimeException('Mikrotik credentials missing on router ID ' . $router->id);
        }

        /** @var \RouterosAPI $API */
        $API = new \RouterosAPI();
        $API->debug = false;
        $API->port  = (int) $apiPort;

        Log::info('VoucherService: connecting to MikroTik via RouterosAPI', [
            'router_id' => $router->id,
            'host'      => $host,
            'port'      => $API->port,
            'user'      => $user,
        ]);

        if (! $API->connect($host, $user, $pass)) {
            Log::error('VoucherService: MikroTik connect failed', [
                'router_id' => $router->id,
                'host'      => $host,
                'port'      => $API->port,
            ]);
            throw new RuntimeException('Failed to connect to MikroTik router.');
        }

        try {
            // THIS is where the "Undefined array key 0" usually comes from.
            $API->comm('/ip/hotspot/user/add', [
                'name'         => $username,
                'password'     => $password,
                'profile'      => $profile,
                'limit-uptime' => $limitUptime,
            ]);

            Log::info('VoucherService: MikroTik hotspot user added', [
                'router_id' => $router->id,
                'username'  => $username,
                'profile'   => $profile,
            ]);
        } catch (\Throwable $e) {
            // If it's only that RouterosAPI notice, LOG & IGNORE (treat as success)
            if (str_contains($e->getMessage(), 'Undefined array key 0')) {
                Log::warning('VoucherService: RouterosAPI notice (Undefined array key 0) ignored', [
                    'router_id' => $router->id,
                    'username'  => $username,
                    'error'     => $e->getMessage(),
                ]);
            } else {
                Log::error('VoucherService: MikroTik user/add failed', [
                    'router_id' => $router->id,
                    'error'     => $e->getMessage(),
                ]);
                throw new RuntimeException('MikroTik user/add failed: ' . $e->getMessage());
            }
        } finally {
            $API->disconnect();
        }
    }

    /**
     * Send SMS using Beem (same idea as your old PHP code).
     */
    protected function sendSuccessSms(Order $order, Plan $plan, string $code): void
    {
        $settings = DB::table('settings')
            ->whereIn('key', ['beem_api_key', 'beem_secret_key', 'beem_sender_name'])
            ->pluck('value', 'key');

        $apiKey   = $settings['beem_api_key']     ?? null;
        $secret   = $settings['beem_secret_key']  ?? null;
        $senderId = $settings['beem_sender_name'] ?? null;

        if (! $apiKey || ! $secret || ! $senderId) {
            Log::warning('Beem SMS not configured, skipping voucher SMS.', [
                'order_id' => $order->id,
            ]);
            return;
        }

        $msg = sprintf(
            "Umefanikiwa kununua kifurushi cha WiFi cha TZS %s (%s). Vocha yako ni: %s. Asante kwa kuchagua BLUEBANDO.",
            number_format($order->amount),
            $plan->name,
            $code
        );

        try {
            Http::withHeaders([
                'Content-Type'  => 'application/json',
                'Authorization' => 'Basic ' . base64_encode($apiKey . ':' . $secret),
            ])->post('https://apisms.beem.africa/v1/send', [
                'source_addr'   => $senderId,
                'encoding'      => 0,
                'schedule_time' => '',
                'message'       => $msg,
                'recipients'    => [
                    ['recipient_id' => 1, 'dest_addr' => $order->phone],
                ],
            ]);

            Log::info('VoucherService: Beem SMS sent', [
                'order_id' => $order->id,
                'phone'    => $order->phone,
            ]);
        } catch (\Throwable $e) {
            Log::error('Beem SMS send failed', [
                'order_id' => $order->id,
                'error'    => $e->getMessage(),
            ]);
        }
    }
}