<?php

use App\Services\Payments\Providers\PolarProvider;

test('polar provider has correct name and capabilities', function () {
    $provider = new PolarProvider;

    expect($provider->getName())->toBe('polar');
    expect($provider->supportsRecurring())->toBeTrue();
    expect($provider->supportsOneTime())->toBeTrue();
    expect($provider->getSupportedCurrencies())->toBe(['USD']);
});

test('polar provider is inactive without api key', function () {
    $provider = new PolarProvider;

    expect($provider->isActive())->toBeFalse();
});

test('polar provider is active with api key', function () {
    $provider = new PolarProvider(['api_key' => 'test-api-key']);

    expect($provider->isActive())->toBeTrue();
});

test('can calculate fees correctly', function () {
    $provider = new PolarProvider;

    $fees = $provider->calculateFees(100.00);

    expect($fees['fixed_fee'])->toBe(0);
    expect($fees['percentage_fee'])->toBe(6.0); // 6% fee
    expect($fees['total_fee'])->toBe(6.0);
    expect($fees['net_amount'])->toBe(94.0);
});

test('can get configuration', function () {
    $config = [
        'api_key' => 'test-api-key',
        'webhook_secret' => 'test-secret',
    ];
    $provider = new PolarProvider($config);

    expect($provider->getConfiguration())->toHaveKey('api_key', 'test-api-key');
    expect($provider->getConfiguration())->toHaveKey('webhook_secret', 'test-secret');
});

test('can validate webhook signature', function () {
    $provider = new PolarProvider(['webhook_secret' => 'test-secret']);

    $request = new \Illuminate\Http\Request([], [], [], [], [], [], 'test-payload');
    $request->headers->set('Polar-Signature', 'test-signature');

    expect($provider->validateWebhook($request))->toBeFalse(); // Invalid signature
});

test('webhook methods return expected values', function () {
    $provider = new PolarProvider;
    $request = new \Illuminate\Http\Request([], [], [], [], [], [], 'test-payload');

    $webhookResult = $provider->processWebhook($request);
    expect($webhookResult['event_type'])->toBe('unknown');
    expect($webhookResult['processed'])->toBeFalse();

    expect($provider->validateWebhook($request))->toBeFalse();
});

test('customer portal returns dashboard when no customer', function () {
    $provider = new PolarProvider;
    $mockUser = new class
    {
        public $id = 1;
    };

    // Should throw exception when no customer exists
    expect($provider->createCustomerPortalSession($mockUser))
        ->toThrow(\Exception::class);
});

test('polar payments are not refundable through API', function () {
    $provider = new PolarProvider;

    expect($provider->processRefund('test_id', 100.00, 'User requested'))
        ->toThrow('Polar refunds must be processed through Polar dashboard or API directly');
});

test('can get supported currencies', function () {
    $provider = new PolarProvider;

    $currencies = $provider->getSupportedCurrencies();
    expect($currencies)->toBe(['USD']);
});

test('has correct method signatures', function () {
    $provider = new PolarProvider;

    // Test that all required methods exist and have correct signatures
    $reflection = new ReflectionClass($provider);

    $methods = [
        'getName' => 0,
        'isActive' => 0,
        'supportsRecurring' => 0,
        'supportsOneTime' => 0,
        'getSupportedCurrencies' => 0,
        'calculateFees' => 1,
        'createSubscription' => 3,
        'cancelSubscription' => 2,
        'updateSubscription' => 2,
        'pauseSubscription' => 1,
        'resumeSubscription' => 1,
        'getSubscriptionDetails' => 1,
        'createCheckoutSession' => 3,
        'createCustomerPortalSession' => 1,
        'processWebhook' => 1,
        'validateWebhook' => 1,
        'getConfiguration' => 0,
        'syncSubscriptionStatus' => 1,
        'getPaymentMethodDetails' => 1,
        'processRefund' => 3,
        'getTransactionHistory' => 2,
        'getSubscriptionMetadata' => 1,
        'updateSubscriptionMetadata' => 2,
        'startTrial' => 2,
        'applyCoupon' => 2,
        'removeCoupon' => 1,
        'getUpcomingInvoice' => 1,
        'retryFailedPayment' => 1,
        'canModifySubscription' => 1,
        'getCancellationTerms' => 1,
        'exportSubscriptionData' => 1,
        'importSubscriptionData' => 2,
    ];

    foreach ($methods as $methodName => $expectedParams) {
        expect($reflection->hasMethod($methodName))->toBeTrue();
        expect($reflection->getMethod($methodName)->getNumberOfParameters())->toBe($expectedParams);
    }
});

test('has correct cancellation terms', function () {
    $provider = new PolarProvider;
    $mockSubscription = new class
    {
        public $id = 1;
    };

    $terms = $provider->getCancellationTerms($mockSubscription);

    expect($terms['immediate_cancellation'])->toBeTrue();
    expect($terms['refund_policy'])->toBe('no_pro_rated_refunds');
    expect($terms['cancellation_effective'])->toBe('immediately');
    expect($terms['billing_cycle_proration'])->toBeFalse();
});

test('can export subscription data', function () {
    $provider = new PolarProvider;
    $mockSubscription = new class
    {
        public $id = 1;

        public $provider_subscription_id = 'test_id';

        public $provider_data = ['test' => 'data'];
    };

    $data = $provider->exportSubscriptionData($mockSubscription);

    expect($data['provider'])->toBe('polar');
    expect($data['provider_subscription_id'])->toBe('test_id');
    expect($data['data'])->toBe(['test' => 'data']);
});

test('cannot import subscription data', function () {
    $provider = new PolarProvider;
    $mockUser = new class
    {
        public $id = 1;
    };
    $subscriptionData = ['provider' => 'polar', 'data' => []];

    expect(fn () => $provider->importSubscriptionData($mockUser, $subscriptionData))
        ->toThrow('Import to Polar payments not implemented');
});

test('cannot start trial after subscription', function () {
    $provider = new PolarProvider;
    $mockSubscription = new class
    {
        public $id = 1;
    };

    expect($provider->startTrial($mockSubscription, 7))->toBeFalse();
});

test('upcoming invoice returns empty data for non-existent subscription', function () {
    $provider = new PolarProvider;
    $mockSubscription = new class
    {
        public $id = 1;
    };

    $invoice = $provider->getUpcomingInvoice($mockSubscription);

    expect($invoice['amount_due'])->toBe(0);
    expect($invoice['currency'])->toBe('USD');
    expect($invoice['next_payment_date'])->toBeNull();
});

test('cannot remove coupon without subscription', function () {
    $provider = new PolarProvider;
    $mockSubscription = new class
    {
        public $id = 1;
    };

    expect($provider->removeCoupon($mockSubscription))->toBeFalse();
});

test('cannot apply coupon without subscription', function () {
    $provider = new PolarProvider;
    $mockSubscription = new class
    {
        public $id = 1;
    };

    expect(fn () => $provider->applyCoupon($mockSubscription, 'DISCOUNT10'))
        ->toThrow(\Throwable::class);
});

test('cannot pause subscription without polar subscription', function () {
    $provider = new PolarProvider;
    $mockSubscription = new class
    {
        public $id = 1;
    };

    expect(fn () => $provider->pauseSubscription($mockSubscription))
        ->toThrow(\Throwable::class);
});

test('cannot resume subscription without polar subscription', function () {
    $provider = new PolarProvider;
    $mockSubscription = new class
    {
        public $id = 1;
    };

    expect(fn () => $provider->resumeSubscription($mockSubscription))
        ->toThrow(\Throwable::class);
});

test('cannot get subscription details without valid id', function () {
    $provider = new PolarProvider;

    expect(fn () => $provider->getSubscriptionDetails('invalid-id'))
        ->toThrow(\Exception::class);
});

test('cannot cancel subscription without subscription', function () {
    $provider = new PolarProvider;
    $mockSubscription = new class
    {
        public $id = 1;
    };

    expect(fn () => $provider->cancelSubscription($mockSubscription, 'test'))
        ->toThrow(\Throwable::class);
});

test('cannot update subscription without subscription', function () {
    $provider = new PolarProvider;
    $mockSubscription = new class
    {
        public $id = 1;
    };
    $mockPlan = new class
    {
        public $id = 1;
    };

    expect(fn () => $provider->updateSubscription($mockSubscription, $mockPlan))
        ->toThrow(\Throwable::class);
});

test('cannot create subscription without plan', function () {
    $provider = new PolarProvider;
    $mockUser = new class
    {
        public $id = 1;
    };

    expect(fn () => $provider->createSubscription($mockUser, null))
        ->toThrow(\TypeError::class);
});
