<?php

namespace App\Classes\Modules\Accounting\ControllersLogic;

use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Accounting\Services\FetchesBankStatementTransaction;
use App\Http\Resources\BankStatementTransactionResource;
use App\Classes\Modules\Accounting\Services\UpdatesBankStatementTransactionOwnerStatus;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\StatementTransactionOwnerType;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\Modules\Accounting\Services\FetchesBankStatementDetails;
use App\Classes\Modules\Accounting\Services\ListsBankStatementDetails;
use App\Models\StatementTransactionOwner;
use Illuminate\Support\Collection;

class ApproveDuplicateBankStatementDetailsStatusLogic extends AbstractControllerLogic
{

    /**
     * @return array
     */
    protected function notification(): array
    {
        return [
            'title' => 'Update Duplicate Bank Statement Details Status',
            'message' => 'You have successfully updated the Statement Transation Status'
        ];
    }

    /** @var UpdatesBankStatementTransactionOwnerStatus */
    private $updatesBankStatementTransactionOwnerStatus;

    /**
     * @param UpdatesBankStatementTransactionOwnerStatus $updatesBankStatementTransactionOwnerStatus
     */
    public function __construct(UpdatesBankStatementTransactionOwnerStatus $updatesBankStatementTransactionOwnerStatus)
    {
        $this->updatesBankStatementTransactionOwnerStatus = $updatesBankStatementTransactionOwnerStatus;
    }

//    /**
//     * Perform logic for approving or rejecting a statement transaction owner and handle matching records.
//     *
//     * @param Request $request The request object containing route parameters and data.
//     * @return JsonResponse The JSON response indicating the result of the logic.
//     */
//    public function logic(Request $request): JsonResponse
//    {
//        // Determine the status based on the 'status' route parameter
//        $status = $request->route('status') == 'approve' ? ApprovalStatus::APPROVED : ApprovalStatus::REJECTED;
//
//        // Find the statement transaction owner based on the 'id' route parameter
//        $owner = StatementTransactionOwner::find($request->route('id'));
//
//        // Execute an update action to change the status of the owner
//        $this->updatesBankStatementTransactionOwnerStatus->execute($owner, $status);
//
//        // If the status is 'approved', reject all other owners with the same system, owner type, and owner ID
//        if ($status === ApprovalStatus::APPROVED) {
//            StatementTransactionOwner::where('system', $owner->system)
//                ->where('owner_type', $owner->owner_type)
//                ->where('owner_id', $owner->owner_id)
//                ->where('id', '!=', $owner->id)
//                ->update(['status' => ApprovalStatus::REJECTED]);
//        }
//
//        // Find all siblings (owners with the same statement transaction ID)
//        $siblings = StatementTransactionOwner::where('statement_transaction_id', $owner->statement_transaction_id)
//            ->where('id', '!=', $owner->id)
//            ->get();
//
//        // Process each sibling
//        foreach ($siblings as $sibling) {
//
//            // If the status is 'approved', reject the sibling and save the changes
//            if ($status === ApprovalStatus::APPROVED) {
//                $sibling->status = ApprovalStatus::REJECTED;
//                $sibling->save();
//            }
//
//            // Find all twins (owners with the same system, owner type, and owner ID)
//            $twins = StatementTransactionOwner::where('system', $sibling->system)
//                ->where('owner_type', $sibling->owner_type)
//                ->where('owner_id', $sibling->owner_id)
//                ->where('id', '!=', $sibling->id)
//                ->get();
//
//            // Process each twin
//            foreach ($twins as $twin) {
//                // Find all owners with the same statement transaction ID as the twin
//                $owners = StatementTransactionOwner::where('statement_transaction_id', $twin->statement_transaction_id)
//                    ->where('id', '!=', $twin->id)
//                    ->get();
//
//                // If there is only one owner (the twin itself), execute an update action to change its status to 'approved'
//                if (count($owners) === 1) {
//                    $this->updatesBankStatementTransactionOwnerStatus->execute($twin, ApprovalStatus::APPROVED);
//                }
//            }
//        }
//
//        // Find all remaining matching owners for the related transaction
//        $remainingMatches = StatementTransactionOwner::where('system', $owner->system)
//            ->where('owner_type', $owner->owner_type)
//            ->where('owner_id', $owner->owner_id)
//            ->where('status', ApprovalStatus::PENDING_VERIFICATION) // Consider only pending owners
//            ->get();
//
//        // Process each remaining match
//        foreach ($remainingMatches as $match) {
//            // Find all owners with the same statement transaction ID as the match
//            $owners = StatementTransactionOwner::where('statement_transaction_id', $match->statement_transaction_id)
//                ->where('id', '!=', $match->id)
//                ->get();
//
//            // If there is only one owner (the match itself), execute an update action to change its status to 'approved'
//            if (count($owners) === 1) {
//                $this->updatesBankStatementTransactionOwnerStatus->execute($match, ApprovalStatus::APPROVED);
//            }
//        }
//
//        // Return an empty response
//        return $this->response([]);
//    }

    /**
     * Perform logic for approving or rejecting a statement transaction owner and handle matching records.
     *
     * @param Request $request The request object containing route parameters and data.
     * @return JsonResponse The JSON response indicating the result of the logic.
     */
    public function logic(Request $request): JsonResponse
    {
        // Determine the approval status
        $status = $this->getConstantStatus($request->route('status'));

        // Find the statement transaction owner
        $owner = $this->getOwner($request);

        // Update owner status
        $this->updateOwnerStatus($owner, $status);

        //  handle the siblings process
        $this->handleSiblingsStatus($owner, $this->getSiblingsStatus($status));

        // Check and approve remaining matches if any
        $this->checkAndApproveRemainingMatches($owner, $status);

        // Return an empty response
        return $this->response([]);
    }

    private function getConstantStatus(String $statusName=null): int
    {
        switch ($statusName) {
            case 'approve':
                return ApprovalStatus::APPROVED;

            case 'pending_verification':
                return ApprovalStatus::PENDING_VERIFICATION;
            
            default:
                return ApprovalStatus::REJECTED;
        }
    }

    private function getSiblingsStatus(int $status): int
    {
        return $status == ApprovalStatus::APPROVED ? ApprovalStatus::REJECTED : ApprovalStatus::PENDING_VERIFICATION;
    }

    private function getOwner(Request $request): StatementTransactionOwner
    {
        return StatementTransactionOwner::find($request->route('id'));
    }

    private function updateOwnerStatus(StatementTransactionOwner $owner, int $status): void
    {
        $this->updatesBankStatementTransactionOwnerStatus->execute($owner, $status);
    }

    private function handleSiblingsStatus(StatementTransactionOwner $owner, int $siblingStatus): void
    {
        // update all other owners with the same system, owner type, and owner ID
        $this->updateOtherOwners($owner, $siblingStatus);

        // Find all siblings and process them
        $siblings = $this->getSiblings($owner);

        foreach ($siblings as $sibling) {
            $this->processSibling($sibling, $siblingStatus);
        }
    }

    private function updateOtherOwners(StatementTransactionOwner $owner, int $status): void
    {
        StatementTransactionOwner::getSiblingsOwner()
            ->where('id', '!=', $owner->id)
            ->update(['status' => $status]);
    }

    private function getSiblings(StatementTransactionOwner $owner): Collection
    {
        return StatementTransactionOwner::where('statement_transaction_id', $owner->statement_transaction_id)
            ->where('id', '!=', $owner->id)
            ->get();
    }

    private function processSibling(StatementTransactionOwner $sibling, int $siblingStatus): void
    {
        // Reject the sibling and save the changes
        $sibling->status = $siblingStatus;
        $sibling->save();
        
        // Find all twins and process them
        $twins = $this->getTwins($sibling);

        foreach ($twins as $twin) {
            $this->processTwin($twin);
        }
    }

    private function getTwins(StatementTransactionOwner $sibling): Collection
    {
        return StatementTransactionOwner::getSiblingsOwner()
            ->where('id', '!=', $sibling->id)
            ->get();
    }

    private function processTwin(StatementTransactionOwner $twin): void
    {
        // Find all owners with the same statement transaction ID as the twin
        $owners = $this->getSiblings($twin);

        // If there is only one owner (the twin itself), approve it
        if ($owners->count() === 1) {
            $this->updateOwnerStatus($twin, $this->getConstantStatus(request()->route('status')));
        }
    }

    private function checkAndApproveRemainingMatches(StatementTransactionOwner $owner, int $status): void
    {
        // Find all remaining matching owners for the related transaction
        $checkStatus = ($status == ApprovalStatus::APPROVED ? ApprovalStatus::PENDING_VERIFICATION : ApprovalStatus::APPROVED);
        $remainingMatches = $this->getRemainingMatches($owner, $checkStatus);

        // Process each remaining match
        foreach ($remainingMatches as $match) {
            $this->processRemainingMatch($match, $status);
        }
    }

    private function getRemainingMatches(StatementTransactionOwner $owner, int $checkStatus): Collection
    {
        return StatementTransactionOwner::getSiblingsOwner()
            ->where('status', $checkStatus)
            ->get();
    }

    private function processRemainingMatch(StatementTransactionOwner $match, int $status): void
    {
        // Find all owners with the same statement transaction ID as the match
        $owners = $this->getSiblings($match);

        // If there is only one owner (the match itself), approve it
        if ($owners->count() === 1) {
            $this->updateOwnerStatus($match, $status);
        }

    }

}
