<?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\Account\FreezeAccountModule as CompanyFreezeAccountModule; 

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

use Carbon\Carbon; 

use Laravel\Sanctum\Sanctum; 

use Tests\TestCase;

class CompanyFreezeAccountTest extends TestCase
{
    use RefreshDatabase;

    private Worker                      $workerCompanyToBeFrozenOwner;
    private Worker                      $workerCompanyFrozenOwner;
    private Worker                      $workerCompanyFrozenProjectManager;
    private Company                     $companyToBeFrozen;
    private Company                     $companyFrozen;
    private CompanySubscriptionRates    $companySubscriptionRate;

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

        //! Setup Worker
        $this->workerCompanyToBeFrozenOwner      = $this->createWorker();
        
        $this->workerCompanyFrozenOwner          = $this->createWorker([ 'password' => 'companyOwner']);
        $this->workerCompanyFrozenProjectManager = $this->createWorker([ 'password' => 'companyProjectManager']);

        //! Setup Company
        $this->companyToBeFrozen = $this->createCompany(
            [
                'is_freezed'   => false,
            ]
        );

        $this->companyFrozen     = $this->createCompany(
            [
                'is_freezed'   => true,
                'date_freezed' => Carbon::now()->subMonth()->format('Y-m-d')
            ]
        );

        //! Setup Company User
        $this->createCompanyUser(
            [
                'company_id'      => $this->companyToBeFrozen->id,
                'worker_id'       => $this->workerCompanyToBeFrozenOwner->id,
                'role_id'         => 1
            ]
        );

        $this->createCompanyUser(
            [
                'company_id'      => $this->companyFrozen->id,
                'worker_id'       => $this->workerCompanyFrozenOwner->id,
                'role_id'         => 1
            ]
        );

        $this->createCompanyUser(
            [
                'company_id'      => $this->companyFrozen->id,
                'worker_id'       => $this->workerCompanyFrozenProjectManager->id,
                'role_id'         => 2
            ]
        );

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

        //! Setup Company Subscription 
        $this->createCompanySubscription(
            [
                'company_id'           => $this->companyToBeFrozen->id,
                'subscription_rate_id' => $this->companySubscriptionRate->id,
                'mode_of_payment'      => 'yearly',
                'is_monthly_expired'   => false,
            ]
        );

        $this->createCompanySubscription(
            [
                'company_id'           => $this->companyFrozen->id,
                'subscription_rate_id' => $this->companySubscriptionRate->id,
                'mode_of_payment'      => 'yearly',
                'duration'             => Carbon::now()->addMonths(1),
                'current_month_paid'   => Carbon::now()->subMonths(1),
                'is_monthly_expired'   => false,
            ]
        );
    }

    /**
     * Create Company via factory
     * 
     * @return Company 
     */
    private function createCompany(array $factoryState = []): Company
    {
        return Company::factory()
            ->state($factoryState) 
            ->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 Check Active Transactions
     * 
     * @return void
     */
    public function test_check_if_has_active_transactions(): void
    {
        $response = (new CompanyFreezeAccountModule())->checkIfHasActiveTransaction($this->companyToBeFrozen->id);

        $this->assertIsArray($response); 

        $this->assertTrue(count($response) == 0, "There are no Active Transactions");
    }

    /**
     * Test Freeze Accouunt
     * 
     * @return void
     */
    public function test_freeze(): void
    {
        Sanctum::actingAs(
            $this->workerCompanyToBeFrozenOwner,
            ['*']
        );

        $response = (new CompanyFreezeAccountModule())->freezeAccount();

        $this->assertIsArray($response);
        $this->assertIsArray($response['activeTransactions']);

        $this->assertTrue(count($response['activeTransactions']) == 0, "There are no Active Transactions");
        $this->assertTrue($response['success'] == true, "Company Account has been successfully frozen");

        $this->assertDatabaseHas(
            Company::class, 
            [
                'id'           => $this->companyToBeFrozen->id,
                'is_freezed'   => true,
                'date_freezed' => Carbon::now()->format('Y-m-d')
            ]
        );
    }

    /**
     * Test Prevent Login
     * 
     * @return void
     */
    public function test_check_if_account_is_frozen(): void
    {
        $response = (new CompanyFreezeAccountModule())->checkIfAccountIsFrozen(
        [ 
                "email"    => $this->workerCompanyFrozenProjectManager->email_address,
                "password" => 'companyProjectManager'
            ]
        );
        
        $this->assertIsArray($response);
        
        $this->assertTrue($response['isFrozen']     == true,  "Company Account is Frozen");
        $this->assertTrue($response['isAuthorized'] == false, "User (Project Manager) is not Authorized to unfreeze Account");

        $response = (new CompanyFreezeAccountModule())->checkIfAccountIsFrozen(
            [
                "email"    => $this->workerCompanyFrozenOwner->email_address,
                "password" => 'companyOwner'
            ]
        );

        $this->assertIsArray($response);

        $this->assertTrue($response['isFrozen']     == true,  "Company Account is Frozen");
        $this->assertTrue($response['isAuthorized'] == true, "User (Company Owner) is Authorized to unfreeze Account"); 
    }

    /**
     * Test Unfreeze Account
     * 
     * @return void
     */
    public function test_unfreeze(): void
    {
        $this->assertDatabaseHas(
            Company::class,
            [
                'id'           => $this->companyFrozen->id,
                'is_freezed'   => true,
                'date_freezed' => $this->companyFrozen->date_freezed
            ]
        );

        $response = (new CompanyFreezeAccountModule())->unFreezeAccount(
            [
                "email"    => $this->workerCompanyFrozenOwner->email_address,
                "password" => 'companyOwner'
            ]
        );

        $this->assertIsArray($response);

        $this->assertTrue($response['success']      == true,  "Company Account Successfully Unfroze");
        $this->assertTrue($response['isAuthorized'] == true, "User (Company Owner) is Authorized to unfreeze Account"); 

        $this->assertDatabaseHas(
            Company::class,
            [
                'id'           => $this->companyFrozen->id,
                'is_freezed'   => false,
            ]
        );
    }

}
