<?php

declare(strict_types=1);

use App\Models\AuditLog;
use App\Models\Plan;
use App\Models\Service;
use App\Models\User;
use Database\Seeders\RoleAndPermissionSeeder;
use Laravel\Cashier\Subscription;

beforeEach(function (): void {
    $this->seed(RoleAndPermissionSeeder::class);

    $this->admin = User::factory()->admin()->create();
    $this->customer = User::factory()->customer()->create();

    $this->plan = Plan::factory()->create([
        'service_type' => 'vps',
        'status' => 'active',
    ]);

    $this->subscription = Subscription::factory()->create([
        'user_id' => $this->customer->id,
        'type' => 'default',
        'stripe_status' => 'active',
        'ends_at' => now()->addDays(30),
    ]);

    $this->service = Service::factory()->create([
        'user_id' => $this->customer->id,
        'subscription_id' => $this->subscription->id,
        'plan_id' => $this->plan->id,
        'service_type' => 'vps',
        'status' => 'active',
        'provisioned_at' => now()->subDays(10),
    ]);
});

test('admin can extend service expiry date', function (): void {
    $newDate = now()->addDays(60)->format('Y-m-d');

    $response = $this->actingAs($this->admin)
        ->post("http://admin.ezscale.dev/services/{$this->service->id}/extend-expiry", [
            'new_expiry_date' => $newDate,
            'reason' => 'Customer loyalty extension',
        ]);

    $response->assertSessionHas('success', 'Service expiry date has been extended successfully.');

    // Verify subscription ends_at was updated
    $this->subscription->refresh();
    expect($this->subscription->ends_at->format('Y-m-d'))->toBe($newDate);
});

test('extend expiry creates audit log with old and new dates', function (): void {
    $oldEndsAt = $this->subscription->ends_at;
    $newDate = now()->addDays(90)->format('Y-m-d');

    $this->actingAs($this->admin)
        ->post("http://admin.ezscale.dev/services/{$this->service->id}/extend-expiry", [
            'new_expiry_date' => $newDate,
            'reason' => 'Goodwill extension',
        ]);

    $auditLog = AuditLog::where('action', 'extend_service_expiry')
        ->where('resource_id', $this->service->id)
        ->first();

    expect($auditLog)->not->toBeNull();
    expect($auditLog->admin_id)->toBe($this->admin->id);
    expect($auditLog->user_id)->toBe($this->customer->id);
    expect($auditLog->resource_type)->toBe('service');
    expect($auditLog->changes)->toHaveKey('old_ends_at');
    expect($auditLog->changes)->toHaveKey('new_ends_at');
    expect($auditLog->changes['reason'])->toBe('Goodwill extension');
});

test('extend expiry requires date in the future', function (): void {
    $pastDate = now()->subDays(5)->format('Y-m-d');

    $response = $this->actingAs($this->admin)
        ->post("http://admin.ezscale.dev/services/{$this->service->id}/extend-expiry", [
            'new_expiry_date' => $pastDate,
        ]);

    $response->assertSessionHasErrors(['new_expiry_date']);
});

test('extend expiry requires a date', function (): void {
    $response = $this->actingAs($this->admin)
        ->post("http://admin.ezscale.dev/services/{$this->service->id}/extend-expiry", [
            'new_expiry_date' => '',
        ]);

    $response->assertSessionHasErrors(['new_expiry_date']);
});

test('extend expiry fails for service without subscription', function (): void {
    $serviceNoSub = Service::factory()->create([
        'user_id' => $this->customer->id,
        'subscription_id' => null,
        'plan_id' => $this->plan->id,
        'service_type' => 'vps',
        'status' => 'active',
    ]);

    $response = $this->actingAs($this->admin)
        ->post("http://admin.ezscale.dev/services/{$serviceNoSub->id}/extend-expiry", [
            'new_expiry_date' => now()->addDays(30)->format('Y-m-d'),
        ]);

    $response->assertSessionHas('error', 'This service does not have an associated subscription.');
});

test('extend expiry works when subscription has no previous ends_at', function (): void {
    $this->subscription->update(['ends_at' => null]);

    $newDate = now()->addDays(45)->format('Y-m-d');

    $response = $this->actingAs($this->admin)
        ->post("http://admin.ezscale.dev/services/{$this->service->id}/extend-expiry", [
            'new_expiry_date' => $newDate,
        ]);

    $response->assertSessionHas('success', 'Service expiry date has been extended successfully.');

    $this->subscription->refresh();
    expect($this->subscription->ends_at->format('Y-m-d'))->toBe($newDate);

    // Audit log should have null for old_ends_at
    $auditLog = AuditLog::where('action', 'extend_service_expiry')->first();
    expect($auditLog->changes['old_ends_at'])->toBeNull();
});

test('extend expiry reason is optional', function (): void {
    $newDate = now()->addDays(60)->format('Y-m-d');

    $response = $this->actingAs($this->admin)
        ->post("http://admin.ezscale.dev/services/{$this->service->id}/extend-expiry", [
            'new_expiry_date' => $newDate,
        ]);

    $response->assertSessionHas('success');

    $auditLog = AuditLog::where('action', 'extend_service_expiry')->first();
    expect($auditLog->changes['reason'])->toBeNull();
});

test('non-admin cannot extend service expiry', function (): void {
    $response = $this->actingAs($this->customer)
        ->post("http://admin.ezscale.dev/services/{$this->service->id}/extend-expiry", [
            'new_expiry_date' => now()->addDays(30)->format('Y-m-d'),
        ]);

    $response->assertForbidden();
});

test('service show page includes subscription data', function (): void {
    $response = $this->actingAs($this->admin)
        ->get("http://admin.ezscale.dev/services/{$this->service->id}");

    $response->assertOk();

    $props = $response->viewData('page')['props'];
    $service = $props['service'];

    expect($service)->toHaveKey('subscription');
    expect($service['subscription'])->not->toBeNull();
    expect($service['subscription'])->toHaveKey('ends_at');
    expect($service['subscription'])->toHaveKey('current_period_end');
    expect($service['subscription'])->toHaveKey('stripe_status');
});
