<?php

namespace Tests\Feature;

use App\Models\Company;
use App\Models\CompanySubscriptionRates;
use App\Models\CompanySubscriptions;
use App\Models\CompanyUser;
use App\Models\Worker;
use App\Modules\Company\Subscription\Payments\MonthlyPayment as CompanySubscriptionPaymentModule;

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

use Carbon\Carbon;

use Laravel\Sanctum\Sanctum;

use Stripe; 

use Tests\TestCase;

class CompanySubscriptionPaymentTest extends TestCase
{
    use RefreshDatabase;

    private Worker                      $workerMonthly; 
    private Worker                      $workerYearly; 
    private Company                     $companyMonthly;
    private Company                     $companyYearly;
    private CompanySubscriptionRates    $companySubscriptionRate;

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

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

        //! Setup Worker
        $this->workerMonthly = $this->createWorker();
        $this->workerYearly  = $this->createWorker(); 

        //! Setup Company
        $this->companyMonthly = $this->createCompany();
        $this->companyYearly  = $this->createCompany();

        //! Setup Company User
        $this->createCompanyUser(
            [
                'company_id'      => $this->companyMonthly->id,
                'worker_id'       => $this->workerMonthly->id
            ]
        );

        $this->createCompanyUser(
            [
                'company_id'      => $this->companyYearly->id,
                'worker_id'       => $this->workerYearly->id
            ]
        );

        //! Setup Subscription Rate
        $this->companySubscriptionRate = $this->createCompanySubscriptionRate(); 

        //! Setup Company Subscription 
        $this->createCompanySubscription(
            [
                'company_id'           => $this->companyMonthly->id,
                'subscription_rate_id' => $this->companySubscriptionRate->id,
                'mode_of_payment'      => 'monthly',
                'is_monthly_expired'   => false,
                'current_month_paid'   => Carbon::now()->subMonth(), 
                'amount_due'           => $this->companySubscriptionRate->monthly_rate
            ]
        );

        $this->createCompanySubscription(
            [
                'company_id'           => $this->companyYearly->id,
                'subscription_rate_id' => $this->companySubscriptionRate->id,
                'mode_of_payment'      => 'yearly',
                'is_monthly_expired'   => false,
                'current_month_paid'   => Carbon::now()->subYear(),
                'amount_due'           => $this->companySubscriptionRate->yearly_rate
            ]
        );
    }

    /**
     * Create Company via factory
     * 
     * @return Company 
     */
    private function createCompany(): Company
    {
        return Company::factory()->create();
    }

    /**
     * Create Company Subscription Rate via factory
     * 
     * @return CompanySubscriptionRates 
     */
    private function createCompanySubscriptionRate(): CompanySubscriptionRates
    {
        return CompanySubscriptionRates::factory()->create();
    }

    /**
     * Create Company Subscription Rate via factory
     * 
     * @param array $factoryState
     * 
     * @return CompanySubscriptions 
     */
    private function createCompanySubscription(array $factoryState = []): CompanySubscriptions
    {
        return  CompanySubscriptions::factory()
            ->state($factoryState)
            ->create();
    }

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

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

    /**
     * Test monthly payment
     * 
     * @return void 
     */
    public function test_payment_monthly(): void
    {
        Sanctum::actingAs(
            $this->workerMonthly,
            ['*']
        );

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

        $response = (new CompanySubscriptionPaymentModule())->payMonthlyBilling(
            [
                "mode"           => "monthly",
                "token"          => $stripeToken,
                "for_date"       => Carbon::now()->format('Y-m-d'),
                "amount_to_pay"  => $this->companySubscriptionRate->monthly_rate,
                "amount_due"     => $this->companySubscriptionRate->monthly_rate,
                "discount"       => 0,
                "previous_bill"  => 0,
                "penalty"        => 0,
                "posted_payment" => 0, 
                'couponCode'     => null
            ]
        );

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

        $this->assertDatabaseHas(
            CompanySubscriptions::class,
            [
                'subscription_rate_id' => $this->companySubscriptionRate->id,
                'company_id'           => $this->companyMonthly->id,
                'mode_of_payment'      => 'monthly',
                'amount_due'           => "0.00",
                'amount_paid'          => $this->companySubscriptionRate->monthly_rate
            ]
        );
    }

    /**
     * Test yearly payment
     * 
     * @return void 
     */
    public function test_payment_yearly(): void
    {
        Sanctum::actingAs(
            $this->workerYearly,
            ['*']
        );

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

        $response = (new CompanySubscriptionPaymentModule())->payMonthlyBilling(
            [
                "mode"           => "yearly",
                "token"          => $stripeToken,
                "for_date"       => Carbon::now()->format('Y-m-d'),
                "amount_to_pay"  => $this->companySubscriptionRate->yearly_rate,
                "amount_due"     => $this->companySubscriptionRate->yearly_rate,
                "discount"       => 0,
                "previous_bill"  => 0,
                "penalty"        => 0,
                "posted_payment" => 0,
                'couponCode'     => null
            ]
        );

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

        $this->assertDatabaseHas(
            CompanySubscriptions::class,
            [
                'subscription_rate_id' => $this->companySubscriptionRate->id,
                'company_id'           => $this->companyYearly->id,
                'mode_of_payment'      => 'yearly',
                'amount_due'           => "0.00", 
                'amount_paid'          => $this->companySubscriptionRate->yearly_rate
            ]
        );
    }
}
