<?php

namespace Tests\Feature;

use App\Models\JobseekerPayment;
use App\Models\Worker; 
use App\Models\JobseekerSubscription; 
use App\Models\JobSeekerSubscriptionRates;
use App\Modules\Jobseeker\Subscription\Payment as JobSeekerSubscriptionPaymentModule;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;

use Carbon\Carbon;

use Laravel\Sanctum\Sanctum;

use Stripe;

use Tests\TestCase;

class JobSeekerSubscriptionTest extends TestCase
{
    use RefreshDatabase;

    private Worker                     $jobSeeker; 
    private Worker                     $jobSeekerExpired; 
    private JobSeekerSubscriptionRates $subscriptionRate; 

    /**
     * Set Up Test
     * 
     * @return void 
     */
    protected function setUp(): void
    {
        parent::setUp();

        //! Setup Stripe 
        Stripe\Stripe::setApiKey(config('stripe.secret_key'));

        //! Setup Job Seeker 
        $this->jobSeeker  = $this->createWorker(
            [
                'worker_id'  => null,
                'date_hired' => null,
            ]
        );

        //! Setup Job Expired 
        $this->jobSeekerExpired = $this->createWorker(
            [
                'worker_id'  => null,
                'date_hired' => null,
            ]
        );

        //! Setup Subscription Rate 
        $this->subscriptionRate = $this->createJobSeekerSubscriptionRate(
            [
                'month' => rand(1, 60)
            ]
        );
    }

    /**
     * Create Worker via factory  
     * 
     * @param array $factoryState 
     * 
     * @return Worker 
     */
    private function createWorker(array $factoryState = []): Worker
    {
        return Worker::factory()
            ->state($factoryState)
            ->create();
    }

    /**
     * Create Job Seeker Subscription via factory  
     * 
     * @param array $factoryState 
     * 
     * @return JobseekerSubscription
     */
    private function createJobSeekerSubscription(array $factoryState = []): JobseekerSubscription
    {
        return JobseekerSubscription::factory()
            ->state($factoryState)
            ->create();
    }

    /**
     * Create Job Seeker Subscription Rate via factory  
     * 
     * @param array $factoryState 
     * 
     * @return JobseekerSubscription
     */
    private function createJobSeekerSubscriptionRate(array $factoryState = []): JobSeekerSubscriptionRates
    {
        return JobSeekerSubscriptionRates::factory()
            ->state($factoryState)
            ->create();
    }

    public function test_set_stripe_api_key() : void  
    {
        $apiKey = Stripe\Stripe::getApiKey();

        $this->assertNotEmpty($apiKey, "Stripe API Key not Empty");
    }

    /**
     * Test Subscription Purchase
     * 
     * @return void 
     */
    public function test_purchase(): void
    {
        Sanctum::actingAs(
            $this->jobSeeker,
            ['*']       
        );

        $this->createJobSeekerSubscription(
            [
                'worker_id'   => $this->jobSeeker->id,
                'rate_id'     => 0,
                'duration'    => Carbon::now(),
                'status'      => 'trial',
                'customer_id' => null,
            ]
        );

        $stripeToken = \Stripe\Token::create(
            [
                "card" => 
                [
                    "number"    => "4242 4242 4242 4242",
                    "exp_month" => "04",
                    "exp_year"  => "24",
                    "cvc"       => "242",
                    "name"      => "test"
                ]
            ]
        );
        
        $response = (new JobSeekerSubscriptionPaymentModule())->buySubscription(
            payload: [ 
                "id"          => $this->subscriptionRate->id,
                "name"        => $this->subscriptionRate->name,
                "description" => $this->subscriptionRate->description,
                "month"       => $this->subscriptionRate->month,
                "rate"        => $this->subscriptionRate->rate,
                "is_disabled" => $this->subscriptionRate->is_disabled,
                "created_at"  => null,
                "updated_at"  => null,
                "deleted_at"  => null,
                "token"       => $stripeToken
            ]
        ); 
        
        $this->assertTrue($response['result'] == 'succeeded', 'Subscription Purchase Success');

        $this->assertDatabaseHas(
            JobseekerPayment::class, 
            [
                'customer_id'=> $this->jobSeeker->id, 
                'invoice_no' => $response['invoice_no'], 
            ]
        );

        $this->assertDatabaseHas(
            JobseekerSubscription::class,
            [
                'worker_id' => $this->jobSeeker->id,
                'rate_id'   => $this->subscriptionRate->id, 
                'duration'  => Carbon::now()->addDays(30 * $this->subscriptionRate->month)->format('Y-m-d'),
                'status'    => 'subscribed'
            ]
        );
    }

    /**
     * Test Subscription Extension
     * 
     * @return void 
     */
    public function test_extension(): void
    {
        Sanctum::actingAs(
            $this->jobSeeker,
            ['*']
        );

        $stripeToken = \Stripe\Token::create(
            [
                "card" =>
                [
                    "number"    => "4242 4242 4242 4242",
                    "exp_month" => "04",
                    "exp_year"  => "24",
                    "cvc"       => "242",
                    "name"      => "test"
                ]
            ]
        );

        $response = (new JobSeekerSubscriptionPaymentModule())->buySubscription(
            payload: [
                "id"          => $this->subscriptionRate->id,
                "name"        => $this->subscriptionRate->name,
                "description" => $this->subscriptionRate->description,
                "month"       => $this->subscriptionRate->month,
                "rate"        => $this->subscriptionRate->rate,
                "is_disabled" => $this->subscriptionRate->is_disabled,
                "created_at"  => null,
                "updated_at"  => null,
                "deleted_at"  => null,
                "token"       => $stripeToken
            ]
        );

        $this->assertTrue($response['result'] == 'succeeded', 'Subscription Extension Success');

        $this->assertDatabaseHas(
            JobseekerPayment::class,
            [
                'customer_id' => $this->jobSeeker->id,
                'invoice_no' => $response['invoice_no'],
            ]
        );

        $this->assertDatabaseHas(
            JobseekerSubscription::class,
            [
                'worker_id' => $this->jobSeeker->id,
                'rate_id'   => $this->subscriptionRate->id,
                'duration'  => Carbon::now()->addDays(30 * $this->subscriptionRate->month)->format('Y-m-d'),
                'status'    => 'subscribed'
            ]
        );
    }

    /**
     * Test Subscription Extension
     * 
     * @return void 
     */
    public function test_renewal(): void
    {
        Sanctum::actingAs(
            $this->jobSeekerExpired,
            ['*']
        );

        $this->createJobSeekerSubscription(
            [
                'worker_id'   => $this->jobSeeker->id,
                'rate_id'     => $this->subscriptionRate->id,
                'duration'    => Carbon::now()->subMonths(rand(1, 12)),
                'status'      => 'expired',
            ]
        );

        $stripeToken = \Stripe\Token::create(
            [
                "card" =>
                [
                    "number"    => "4242 4242 4242 4242",
                    "exp_month" => "04",
                    "exp_year"  => "24",
                    "cvc"       => "242",
                    "name"      => "test"
                ]
            ]
        );

        $response = (new JobSeekerSubscriptionPaymentModule())->buySubscription(
            payload: [
                "id"          => $this->subscriptionRate->id,
                "name"        => $this->subscriptionRate->name,
                "description" => $this->subscriptionRate->description,
                "month"       => $this->subscriptionRate->month,
                "rate"        => $this->subscriptionRate->rate,
                "is_disabled" => $this->subscriptionRate->is_disabled,
                "created_at"  => null,
                "updated_at"  => null,
                "deleted_at"  => null,
                "token"       => $stripeToken
            ]
        );

        $this->assertTrue($response['result'] == 'succeeded', 'Subscription Renewal Success');

        $this->assertDatabaseHas(
            JobseekerPayment::class,
            [
                'customer_id' => $this->jobSeekerExpired->id,
                'invoice_no' => $response['invoice_no'],
            ]
        );

        $this->assertDatabaseHas(
            JobseekerSubscription::class,
            [
                'worker_id' => $this->jobSeekerExpired->id,
                'rate_id'   => $this->subscriptionRate->id,
                'duration'  => Carbon::now()->addDays(30 * $this->subscriptionRate->month)->format('Y-m-d'),
                'status'    => 'subscribed'
            ]
        );
    }
}
