<?php

use App\Models\Plan;
use App\Models\User;
use App\Services\Payments\Providers\ActivationKeyProvider;

test('activation key provider has correct name and capabilities', function () {
    $provider = new ActivationKeyProvider;

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

test('can generate unique activation key', function () {
    $provider = new ActivationKeyProvider;
    $user = User::factory()->create();
    $plan = Plan::factory()->create(['price' => 50.00]);

    $subscription = $provider->createSubscription($user, $plan);

    expect($subscription['provider_subscription_id'])->not->toBeEmpty();
    expect($subscription['status'])->toBe('pending_activation');
    expect($subscription['activation_key'])->not->toBeEmpty();
    expect($subscription['activation_key'])->toStartWith('AK-');
    expect($subscription['type'])->toBe('activation_key');
    expect($subscription['plan_name'])->toBe($plan->name);
    expect($subscription['plan_price'])->toBe(50.00);
});

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

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

    expect($fees['fixed_fee'])->toBe(0);
    expect($fees['percentage_fee'])->toBe(0);
    expect($fees['total_fee'])->toBe(0);
    expect($fees['net_amount'])->toBe(100.00);
});

test('can get subscription details', function () {
    $provider = new ActivationKeyProvider;
    $user = User::factory()->create();
    $plan = Plan::factory()->create();

    $subscription = $provider->createSubscription($user, $plan);
    $details = $provider->getSubscriptionDetails($subscription['provider_subscription_id']);

    expect($details['id'])->toBe($subscription['provider_subscription_id']);
    expect($details['activation_key'])->toBe($subscription['activation_key']);
    expect($details['user_id'])->toBe($user->id);
    expect($details['price_id'])->toBe($plan->id);
    expect($details['is_activated'])->toBeFalse();
});

test('activation keys are not refundable', function () {
    $provider = new ActivationKeyProvider;

    expect(fn () => $provider->processRefund('test_id', 100.00, 'User requested'))
        ->toThrow(Exception::class, 'Activation keys are not refundable');
});

test('can get transaction history', function () {
    $provider = new ActivationKeyProvider;
    $user = User::factory()->create();
    $plan = Plan::factory()->create();

    // Create a few activation keys
    $provider->createSubscription($user, $plan);
    $provider->createSubscription($user, $plan);

    $history = $provider->getTransactionHistory($user);

    expect($history)->toBeArray();
    expect($history)->toHaveCount(2);
    expect($history[0])->toHaveKey('activation_key');
    expect($history[0])->toHaveKey('is_activated');
    expect($history[0])->toHaveKey('created_at');
});

test('can get transaction history with filters', function () {
    $provider = new ActivationKeyProvider;
    $user = User::factory()->create();
    $plan = Plan::factory()->create();

    // Create activation keys
    $subscription1 = $provider->createSubscription($user, $plan);

    // Test filter for unactivated keys (all should be unactivated initially)
    $unactivatedHistory = $provider->getTransactionHistory($user, ['status' => 'unactivated']);
    expect($unactivatedHistory)->toHaveCount(1);
    expect($unactivatedHistory[0]['is_activated'])->toBeFalse();
});

test('can redeem activation key', function () {
    $provider = new ActivationKeyProvider;
    $user = User::factory()->create();
    $plan = Plan::factory()->create();

    // Create activation key
    $subscription = $provider->createSubscription($user, $plan);
    $activationKey = $subscription['activation_key'];

    // Redeem the key
    $result = $provider->redeemActivationKey($activationKey, $user);

    expect($result['success'])->toBeTrue();
    expect($result['plan_name'])->toBe($plan->name);
    expect($result['message'])->toBe('Activation key redeemed successfully');
});

test('cannot redeem already activated key', function () {
    $provider = new ActivationKeyProvider;
    $user = User::factory()->create();
    $plan = Plan::factory()->create();

    // Create and redeem activation key
    $subscription = $provider->createSubscription($user, $plan);
    $activationKey = $subscription['activation_key'];
    $provider->redeemActivationKey($activationKey, $user);

    // Try to redeem again
    expect(fn () => $provider->redeemActivationKey($activationKey, $user))
        ->throw();
});

test('can get configuration', function () {
    $config = [
        'key_prefix' => 'TEST-',
        'key_length' => 16,
        'expiration_days' => 365,
    ];
    $provider = new ActivationKeyProvider($config);

    expect($provider->getConfiguration())->toHaveKey('key_prefix', 'TEST-');
    expect($provider->getConfiguration())->toHaveKey('key_length', 16);
    expect($provider->getConfiguration())->toHaveKey('expiration_days', 365);
});

test('webhook methods return expected values', function () {
    $provider = new ActivationKeyProvider;
    $request = new Illuminate\Http\Request;

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

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

test('customer portal returns dashboard', function () {
    $provider = new ActivationKeyProvider;
    $mockUser = new stdClass;

    $portal = $provider->createCustomerPortalSession($mockUser);

    expect($portal)->toHaveKey('portal_url');
    expect($portal)->toHaveKey('message');
    expect($portal['message'])->toBe('Activation keys are managed through your dashboard');
});

test('cannot update subscription plan', function () {
    $provider = new ActivationKeyProvider;
    $user = User::factory()->create();
    $plan1 = Plan::factory()->create();
    $plan2 = Plan::factory()->create();

    $subscriptionData = $provider->createSubscription($user, $plan1);

    expect(fn () => $provider->updateSubscription(
        new class($subscriptionData['provider_subscription_id'])
        {
            public $provider_subscription_id;

            public function __construct($id)
            {
                $this->provider_subscription_id = $id;
            }
        },
        $plan2
    ))->toThrow('Activation keys do not support plan updates');
});

test('cannot pause or resume subscription', function () {
    $provider = new ActivationKeyProvider;
    $mockSubscription = new class
    {
        public $id = 1;
    };

    expect($provider->pauseSubscription($mockSubscription))->toBeFalse();
    expect($provider->resumeSubscription($mockSubscription))->toBeFalse();
});

test('does not support trials or coupons', function () {
    $provider = new ActivationKeyProvider;
    $mockSubscription = new class
    {
        public $id = 1;
    };

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

    expect(fn () => $provider->applyCoupon($mockSubscription, 'DISCOUNT10'))
        ->toThrow(Exception::class, 'Coupons not supported for activation keys');
});

test('upcoming invoice returns empty data', function () {
    $provider = new ActivationKeyProvider;
    $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('has correct cancellation terms', function () {
    $provider = new ActivationKeyProvider;
    $mockSubscription = new class
    {
        public $id = 1;
    };

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

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

test('can export subscription data', function () {
    $provider = new ActivationKeyProvider;
    $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('activation_key');
    expect($data['provider_subscription_id'])->toBe('test_id');
    expect($data['data'])->toBe(['test' => 'data']);
});

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

    expect(fn () => $provider->importSubscriptionData($mockUser, $subscriptionData))
        ->toThrow(Exception::class, 'Import to activation keys not implemented');
});

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

    // 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,
        'redeemActivationKey' => 2,
    ];

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