<?php

use App\Models\Subscription;

function validSubscriptionPayload(array $overrides = []): array
{
    return array_merge([
        'website' => '',
        'fullName' => 'Ravi Shah',
        'phone' => '9876543210',
        'email' => 'ravi@example.com',
        'whatsapp' => '9876543210',
        'address' => '123 Flower Street, Near Garden City Mall, Surat',
        'city' => 'Surat',
        'pincode' => '395002',
        'landmark' => 'Near the garden',
        'plan' => 'basic',
        'startDate' => now()->format('Y-m-d'),
        'specialInstructions' => 'Leave at the gate',
        'terms' => true,
        'promoEmails' => true,
    ], $overrides);
}

test('a valid subscription is stored and returns the legacy success shape', function () {
    $response = $this->postJson(route('api.subscription'), validSubscriptionPayload());

    $response->assertOk();
    $response->assertJsonStructure([
        'success', 'message', 'data' => ['orderId', 'insertId', 'customerName', 'plan', 'startDate'],
    ]);
    $response->assertJson([
        'success' => true,
        'message' => 'Subscription created successfully!',
    ]);

    $subscription = Subscription::query()->sole();

    expect($response->json('data.orderId'))->toBe($subscription->order_id)
        ->and($response->json('data.insertId'))->toBe($subscription->id)
        ->and($response->json('data.customerName'))->toBe('Ravi Shah')
        ->and($response->json('data.plan'))->toBe('Basic')
        ->and($subscription->order_id)->toMatch('/^PVF-SUB-[A-Z0-9]{8}$/')
        ->and($subscription->terms_agreed)->toBeTrue()
        ->and($subscription->order_status->value)->toBe('pending');
});

test('a honeypot-filled subscription fakes success and stores nothing', function () {
    $response = $this->postJson(route('api.subscription'), validSubscriptionPayload([
        'website' => 'https://spam.example.com',
    ]));

    $response->assertOk();
    $response->assertJson([
        'success' => true,
        'message' => 'Subscription created successfully!',
        'data' => [
            'insertId' => 0,
            'customerName' => 'Ravi Shah',
            'plan' => 'Basic',
        ],
    ]);
    expect($response->json('data.orderId'))->toMatch('/^PVF-SUB-[A-Z0-9]{8}$/');

    expect(Subscription::query()->count())->toBe(0);
});

test('malformed JSON returns a 400', function () {
    $response = $this->call('POST', route('api.subscription'), [], [], [], [
        'CONTENT_TYPE' => 'application/json',
    ], '{not valid json');

    $response->assertStatus(400);
    $response->assertJson([
        'success' => false,
        'message' => 'Invalid JSON data',
        'data' => null,
    ]);
});

test('a subscription phone starting with a leading 5 is rejected', function () {
    $response = $this->postJson(route('api.subscription'), validSubscriptionPayload([
        'phone' => '5987654321',
    ]));

    $response->assertStatus(422);
    $response->assertJsonMissingPath('errors');
    $response->assertJson([
        'success' => false,
        'message' => 'Invalid phone number format',
        'data' => null,
    ]);
});

test('a subscription is rejected when terms is the string "on" instead of true', function () {
    $response = $this->postJson(route('api.subscription'), validSubscriptionPayload([
        'terms' => 'on',
    ]));

    $response->assertStatus(422);
    $response->assertJson([
        'success' => false,
        'message' => 'You must agree to terms and conditions',
        'data' => null,
    ]);

    expect(Subscription::query()->count())->toBe(0);
});

test('subscription validation errors are collected and joined into one message', function () {
    $response = $this->postJson(route('api.subscription'), validSubscriptionPayload([
        'phone' => '5987654321',
        'city' => '',
    ]));

    $response->assertStatus(422);
    $response->assertJson([
        'success' => false,
        'message' => 'Invalid phone number format, City is required',
    ]);
});

test('plan_price is always derived server-side and ignores client-supplied price', function () {
    $response = $this->postJson(route('api.subscription'), validSubscriptionPayload([
        'plan' => 'luxury',
        'planPrice' => 1,
        'plan_price' => 1,
    ]));

    $response->assertOk();

    $subscription = Subscription::query()->sole();

    expect((float) $subscription->plan_price)->toBe(900.00);
});

test('a duplicate subscription for the same phone, plan, and start date is rejected with a 409', function () {
    $payload = validSubscriptionPayload();

    $this->postJson(route('api.subscription'), $payload)->assertOk();

    $response = $this->postJson(route('api.subscription'), $payload);

    $response->assertStatus(409);
    $response->assertJson([
        'success' => false,
        'message' => 'We already have a subscription request for this number, plan and start date. We will call you shortly to confirm.',
        'data' => null,
    ]);

    expect(Subscription::query()->count())->toBe(1);
});

test('the subscription endpoint rate limits after 30 attempts per hour regardless of validity', function () {
    for ($i = 0; $i < 30; $i++) {
        $this->postJson(route('api.subscription'), ['website' => '']);
    }

    $response = $this->postJson(route('api.subscription'), ['website' => '']);

    $response->assertStatus(429);
    $response->assertJson([
        'success' => false,
        'message' => 'Too many attempts. Please call us on 9879991799 and we will set this up for you.',
    ]);
});

test('the subscription endpoint rate limits after 10 stored orders per hour', function () {
    for ($i = 0; $i < 10; $i++) {
        $response = $this->postJson(route('api.subscription'), validSubscriptionPayload([
            'phone' => '98765'.str_pad((string) $i, 5, '0', STR_PAD_LEFT),
        ]));

        $response->assertOk();
    }

    $response = $this->postJson(route('api.subscription'), validSubscriptionPayload([
        'phone' => '9876599999',
    ]));

    $response->assertStatus(429);
    $response->assertJson([
        'success' => false,
        'message' => 'You have already submitted several subscriptions. Please call us on 9879991799 and we will set this up for you.',
    ]);

    expect(Subscription::query()->count())->toBe(10);
});
